-4. **Test A2A Interactions**: For example:
+4. **Test Enhanced A2A Interactions**: For example:
- **General**: "Hi, who are you?" (Handled by Cora via A2A protocol)
- **Inventory**: "Do you have the classic leather sofa in stock?" (Routed through A2A to Inventory Agent)
- **Design**: "What colors of green paint do you have?" (A2A task delegation to Design Agent)
- - **Multi-Agent**: "Find a sofa and check my loyalty points" (A2A coordination between multiple agents)
+ - **Product Recommendations**: "Recommend modern furniture for my living room" (Product Manager delegates to Marketing Agent)
+ - **Product Comparisons**: "Compare sectional sofas" (Product Manager delegates to Ranker Agent)
+ - **Product Details**: "What are the specifications of product SOFA-001?" (Product Manager uses Product Information Plugin)
+ - **Multi-Agent**: "Find a sofa, check reviews, and verify my loyalty points" (Complex A2A coordination across multiple specialized agents)
diff --git a/src/a2a/.env_automation b/src/a2a/.env_automation
index b857e45..e06904f 100644
--- a/src/a2a/.env_automation
+++ b/src/a2a/.env_automation
@@ -4,11 +4,11 @@ A2A_PORT=8001
A2A_LOG_LEVEL=INFO
# Base application URL for monitoring
-BASE_APP_URL=https://zava-72910920-app.azurewebsites.net
+BASE_APP_URL=https://zava-51c07969-app.azurewebsites.net
# Azure monitoring integration
-APPLICATION_INSIGHTS_CONNECTION_STRING=InstrumentationKey=cd157009-2ed7-472b-9bcf-9f83189fe438;IngestionEndpoint=https://westus3-1.in.applicationinsights.azure.com/;LiveEndpoint=https://westus3.livediagnostics.monitor.azure.com/;ApplicationId=43df942d-375b-4d95-b0b4-a85f1045018c
-LOG_ANALYTICS_WORKSPACE_ID=9a4604f5-a37e-4fc6-9c14-73d1d63e88d7
+APPLICATION_INSIGHTS_CONNECTION_STRING=InstrumentationKey=3ecb7f2d-bf9b-4c15-973f-39e820e44b10;IngestionEndpoint=https://westus3-1.in.applicationinsights.azure.com/;LiveEndpoint=https://westus3.livediagnostics.monitor.azure.com/;ApplicationId=c47cdc80-ebeb-4b09-a7f5-4f9b6c9502dc
+LOG_ANALYTICS_WORKSPACE_ID=d3733137-0fd4-48ea-ad35-e3d066ec4d0b
# Automation features
ENABLE_PROCESS_MANAGEMENT=true
diff --git a/src/a2a/agent/__init__.py b/src/a2a/agent/__init__.py
index beca77a..1ef1d7a 100644
--- a/src/a2a/agent/__init__.py
+++ b/src/a2a/agent/__init__.py
@@ -6,7 +6,8 @@
ZavaAgentAdapter, InteriorDesignAgentAdapter, InventoryAgentAdapter,
CustomerLoyaltyAgentAdapter, CartManagementAgentAdapter, CoraAgentAdapter
)
-from .coordinator import A2ACoordinatorAgent, EnhancedProductManagementAgent
+from .coordinator import A2ACoordinatorAgent, EnhancedProductManagementAgent as CoordinatorEnhancedAgent
+from .product_management_agent import EnaganecedProductManagementAgent
__all__ = [
"ZavaAgentAdapter",
@@ -16,5 +17,5 @@
"CartManagementAgentAdapter",
"CoraAgentAdapter",
"A2ACoordinatorAgent",
- "EnhancedProductManagementAgent"
+ "EnaganecedProductManagementAgent"
]
\ No newline at end of file
diff --git a/src/a2a/agent/coordinator.py b/src/a2a/agent/coordinator.py
index be432ed..221fde1 100644
--- a/src/a2a/agent/coordinator.py
+++ b/src/a2a/agent/coordinator.py
@@ -27,6 +27,7 @@
CartManagementAgentAdapter, CoraAgentAdapter
)
+
# Import existing handoff service
import sys
import os
@@ -197,7 +198,7 @@ def _simple_classification(self, user_message: str) -> Dict[str, Any]:
best_domain = max(scores, key=scores.get)
confidence = min(0.8, scores[best_domain] * 0.2) # Max 0.8 confidence
else:
- best_domain = "cora" # Default fallback
+ best_domain = "product_management" # Default to product management
confidence = 0.3
return {
@@ -215,8 +216,8 @@ async def _route_to_agent(
) -> None:
"""Route request to the appropriate agent"""
if domain not in self.agents:
- logger.warning(f"Unknown domain: {domain}, falling back to cora")
- domain = "cora"
+ logger.warning(f"Unknown domain: {domain}, falling back to product_management")
+ domain = "product_management"
target_agent = self.agents[domain]
self.active_handoffs[task.id] = domain
diff --git a/src/a2a/main.py b/src/a2a/main.py
index 82396bc..868205d 100644
--- a/src/a2a/main.py
+++ b/src/a2a/main.py
@@ -37,7 +37,7 @@
from a2a.api import A2AChatRouter, A2AServerRouter
from a2a.api.enhanced_chat_router import EnhancedA2AChatRouter
from a2a.server import A2AStarletteApplication, DefaultRequestHandler
-from a2a.agent import EnhancedProductManagementAgent
+from a2a.agent import EnaganecedProductManagementAgent
from a2a.types import AgentCard, AgentCapabilities, AgentSkill
# Import legacy components for hybrid mode
diff --git a/src/a2a/status_automation.ps1 b/src/a2a/status_automation.ps1
index 49ed770..54430f6 100644
--- a/src/a2a/status_automation.ps1
+++ b/src/a2a/status_automation.ps1
@@ -11,7 +11,7 @@ if () {
# Check automation endpoint
try {
- = Invoke-RestMethod -Uri "https://zava-72910920-app.azurewebsites.net/a2a/automation/status" -TimeoutSec 5
+ = Invoke-RestMethod -Uri "https://zava-51c07969-app.azurewebsites.net/a2a/automation/status" -TimeoutSec 5
Write-Host "Automation Status: "
} catch {
Write-Host "Automation endpoint not accessible"
diff --git a/src/app/agents/a2a_integration.py b/src/app/agents/a2a_integration.py
new file mode 100644
index 0000000..f1b258c
--- /dev/null
+++ b/src/app/agents/a2a_integration.py
@@ -0,0 +1,337 @@
+"""
+Microsoft Foundry Agent Integration for A2A Protocol
+
+This script demonstrates how to integrate the Product Management Agent
+as the 6th agent in your existing Microsoft Foundry setup, following
+A2A protocol patterns with native Agent Framework orchestration.
+"""
+import asyncio
+import json
+import logging
+import os
+from typing import Dict, List, Optional
+from datetime import datetime
+
+from agent_framework import (
+ ChatAgent,
+ ChatMessage,
+ Executor,
+ Role,
+ WorkflowBuilder,
+ WorkflowContext,
+ WorkflowOutputEvent,
+ handler,
+)
+from agent_framework_azure_ai import AzureAIAgentClient
+from azure.identity.aio import DefaultAzureCredential
+
+from product_management_agent import ProductManagementAgentExecutor, create_product_management_workflow
+
+# Setup logging
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+class A2AMultiAgentCoordinator(Executor):
+ """
+ A2A Protocol Coordinator for managing handoffs between all 6 agents:
+ 1. Shopping Assistant (original)
+ 2. Cart Management (original)
+ 3. Customer Loyalty (original)
+ 4. Interior Designer (original)
+ 5. Inventory (original)
+ 6. Product Management (new - this implementation)
+ """
+
+ def __init__(self, foundry_agents: Dict[str, str], id: str = "a2a_coordinator"):
+ """
+ Initialize with references to existing Microsoft Foundry agents
+
+ Args:
+ foundry_agents: Dictionary mapping agent types to their Foundry agent IDs
+ """
+ self.foundry_agents = foundry_agents
+ super().__init__(id=id)
+
+ @handler
+ async def coordinate_request(
+ self, message: ChatMessage, ctx: WorkflowContext[list[ChatMessage], str]
+ ) -> None:
+ """
+ Implement A2A protocol coordination between all 6 agents
+ """
+ try:
+ user_request = message.text.lower()
+ messages: list[ChatMessage] = [message]
+
+ # A2A Protocol: Intelligent Agent Routing
+ routing_decision = await self._determine_primary_agent(user_request)
+
+ coordination_response = ChatMessage(
+ Role.ASSISTANT,
+ text=f"A2A Coordination: Routing to {routing_decision['primary_agent']} agent. "
+ f"Confidence: {routing_decision['confidence']:.2f}. "
+ f"Handoff plan: {routing_decision['handoff_sequence']}"
+ )
+
+ messages.append(coordination_response)
+
+ # Execute the routing plan
+ result = await self._execute_agent_sequence(routing_decision, user_request)
+
+ final_response = f"A2A Protocol executed successfully. Primary agent: {routing_decision['primary_agent']}. Result: {result}"
+ await ctx.yield_output(final_response)
+
+ except Exception as e:
+ error_msg = f"A2A Coordination error: {str(e)}"
+ logger.error(error_msg)
+ await ctx.yield_output(error_msg)
+
+ async def _determine_primary_agent(self, request: str) -> Dict:
+ """
+ A2A Protocol: Determine which agent should handle the request and plan handoffs
+ """
+
+ # Agent capability mapping
+ agent_patterns = {
+ "product_management": {
+ "keywords": ["product", "catalog", "search", "find", "recommend", "compare",
+ "marketing", "trend", "rank", "best", "popular", "specification"],
+ "capabilities": ["product_search", "recommendations", "market_analysis", "rankings"],
+ "confidence_boost": 0.1 # New agent gets priority for product queries
+ },
+ "interior_design": {
+ "keywords": ["design", "color", "paint", "room", "style", "decor",
+ "furniture", "interior", "aesthetic", "layout"],
+ "capabilities": ["room_design", "color_consultation", "style_advice"],
+ "confidence_boost": 0.0
+ },
+ "inventory": {
+ "keywords": ["stock", "available", "inventory", "in store", "quantity",
+ "do you have", "is there", "availability"],
+ "capabilities": ["stock_check", "availability", "inventory_management"],
+ "confidence_boost": 0.0
+ },
+ "customer_loyalty": {
+ "keywords": ["discount", "loyalty", "points", "member", "reward",
+ "savings", "deal", "promotion"],
+ "capabilities": ["loyalty_programs", "discounts", "member_benefits"],
+ "confidence_boost": 0.0
+ },
+ "cart_management": {
+ "keywords": ["cart", "add", "remove", "purchase", "buy", "checkout",
+ "order", "item", "basket"],
+ "capabilities": ["cart_operations", "checkout", "order_management"],
+ "confidence_boost": 0.0
+ },
+ "shopping_assistant": {
+ "keywords": ["help", "information", "question", "what is", "tell me about",
+ "general", "cora"],
+ "capabilities": ["general_assistance", "information", "guidance"],
+ "confidence_boost": 0.0
+ }
+ }
+
+ # Calculate confidence scores
+ scores = {}
+ for agent, config in agent_patterns.items():
+ score = 0.0
+
+ # Keyword matching
+ for keyword in config["keywords"]:
+ if keyword in request:
+ score += 1.0
+
+ # Normalize by keyword count
+ score = score / len(config["keywords"]) if config["keywords"] else 0.0
+
+ # Apply confidence boost
+ score += config["confidence_boost"]
+
+ scores[agent] = score
+
+ # Determine primary agent
+ primary_agent = max(scores.keys(), key=lambda k: scores[k])
+ max_confidence = scores[primary_agent]
+
+ # Plan handoff sequence based on request complexity
+ handoff_sequence = self._plan_handoff_sequence(request, primary_agent)
+
+ return {
+ "primary_agent": primary_agent,
+ "confidence": max_confidence,
+ "all_scores": scores,
+ "handoff_sequence": handoff_sequence
+ }
+
+ def _plan_handoff_sequence(self, request: str, primary_agent: str) -> List[str]:
+ """Plan the sequence of agent handoffs for complex requests"""
+
+ sequence = [primary_agent]
+
+ # Complex request patterns that require multiple agents
+ if "room" in request and "furniture" in request:
+ # Interior design + product management coordination
+ if primary_agent != "interior_design":
+ sequence.append("interior_design")
+ if primary_agent != "product_management":
+ sequence.append("product_management")
+
+ elif any(word in request for word in ["buy", "purchase", "order"]) and primary_agent != "cart_management":
+ # Any product query that leads to purchase intent
+ sequence.append("inventory") # Check availability
+ sequence.append("cart_management") # Handle purchase
+
+ elif "discount" in request or "deal" in request:
+ # Loyalty coordination for any request involving savings
+ if primary_agent != "customer_loyalty":
+ sequence.append("customer_loyalty")
+
+ return sequence
+
+ async def _execute_agent_sequence(self, routing_decision: Dict, request: str) -> str:
+ """Execute the planned agent sequence (simulation for now)"""
+
+ primary_agent = routing_decision["primary_agent"]
+ sequence = routing_decision["handoff_sequence"]
+
+ execution_log = []
+
+ for agent in sequence:
+ if agent in self.foundry_agents:
+ foundry_agent_id = self.foundry_agents[agent]
+ execution_log.append(f"{agent} (Foundry ID: {foundry_agent_id})")
+ else:
+ execution_log.append(f"{agent} (Framework Implementation)")
+
+ return f"Executed sequence: {' ā '.join(execution_log)}"
+
+class ZavaA2AWorkflowManager:
+ """
+ Main workflow manager that coordinates all 6 agents using A2A protocol
+ """
+
+ def __init__(self, foundry_config: Dict[str, str]):
+ """
+ Initialize with Microsoft Foundry configuration
+
+ Args:
+ foundry_config: Configuration containing endpoint, deployment, and agent IDs
+ """
+ self.foundry_config = foundry_config
+ self.workflow = None
+
+ async def initialize_workflow(self):
+ """Initialize the complete A2A workflow with all 6 agents"""
+
+ try:
+ # Create the Product Management Agent executor
+ product_workflow = await create_product_management_workflow(
+ self.foundry_config["endpoint"],
+ self.foundry_config["model_deployment"]
+ )
+
+ # Create A2A coordinator with existing Foundry agent references
+ foundry_agents = {
+ "shopping_assistant": self.foundry_config.get("cora_agent_id", "asst_local_cora"),
+ "interior_design": self.foundry_config.get("interior_agent_id", "asst_local_interior_design"),
+ "inventory": self.foundry_config.get("inventory_agent_id", "asst_local_inventory"),
+ "customer_loyalty": self.foundry_config.get("loyalty_agent_id", "asst_local_customer_loyalty"),
+ "cart_management": self.foundry_config.get("cart_agent_id", "asst_local_cart_management")
+ }
+
+ coordinator = A2AMultiAgentCoordinator(foundry_agents)
+
+ # Build complete workflow with A2A coordination
+ self.workflow = (
+ WorkflowBuilder()
+ .set_start_executor(coordinator)
+ .add_edge(coordinator, product_workflow.build()) # Integration point
+ .build()
+ )
+
+ logger.info("A2A Workflow initialized with 6 agents and coordination")
+
+ except Exception as e:
+ logger.error(f"Failed to initialize A2A workflow: {e}")
+ raise
+
+ async def process_request(self, user_message: str) -> str:
+ """Process a user request through the A2A workflow"""
+
+ if not self.workflow:
+ await self.initialize_workflow()
+
+ try:
+ message = ChatMessage(Role.USER, text=user_message)
+
+ logger.info(f"Processing A2A request: {user_message}")
+
+ async for event in self.workflow.run_stream(message):
+ if isinstance(event, WorkflowOutputEvent):
+ return event.data
+
+ return "A2A workflow completed successfully"
+
+ except Exception as e:
+ logger.error(f"Error processing A2A request: {e}")
+ return f"Error: {str(e)}"
+
+async def main():
+ """
+ Example usage of the complete A2A multi-agent system
+ """
+
+ # Configuration that would come from your .env file
+ foundry_config = {
+ "endpoint": os.getenv("FOUNDRY_ENDPOINT", ""),
+ "model_deployment": os.getenv("MODEL_DEPLOYMENT", "gpt-4o-mini"),
+
+ # Existing Microsoft Foundry agent IDs
+ "cora_agent_id": os.getenv("CORA_AGENT_ID", "asst_local_cora"),
+ "interior_agent_id": os.getenv("INTERIOR_AGENT_ID", "asst_local_interior_design"),
+ "inventory_agent_id": os.getenv("INVENTORY_AGENT_ID", "asst_local_inventory"),
+ "loyalty_agent_id": os.getenv("LOYALTY_AGENT_ID", "asst_local_customer_loyalty"),
+ "cart_agent_id": os.getenv("CART_AGENT_ID", "asst_local_cart_management")
+ }
+
+ if not foundry_config["endpoint"]:
+ print("ā Please set FOUNDRY_ENDPOINT environment variable")
+ return
+
+ try:
+ # Initialize the A2A workflow manager
+ workflow_manager = ZavaA2AWorkflowManager(foundry_config)
+ await workflow_manager.initialize_workflow()
+
+ # Test A2A protocol with different types of requests
+ test_requests = [
+ "I need modern furniture for my living room",
+ "What's the most popular sofa this season?",
+ "Add this chair to my cart and check for member discounts",
+ "Do you have the blue accent chair in stock?",
+ "Design a cozy reading nook with complementary furniture"
+ ]
+
+ print("š Testing Zava A2A Multi-Agent System (6 agents)")
+ print("=" * 60)
+
+ for i, request in enumerate(test_requests, 1):
+ print(f"\\nš Test {i}: {request}")
+ result = await workflow_manager.process_request(request)
+ print(f"ā
Result: {result}")
+
+ print("\\nš All A2A protocol tests completed successfully!")
+
+ # Summary
+ print("\\nš A2A System Summary:")
+ print("⢠6 Coordinated Agents: Shopping, Cart, Loyalty, Interior, Inventory, Product Management")
+ print("⢠Agent Framework Integration: Native Microsoft Foundry orchestration")
+ print("⢠Semantic Kernel Plugins: ProductPlugin, MarketingPlugin, RankingPlugin")
+ print("⢠A2A Protocol: Intelligent routing and handoff coordination")
+
+ except Exception as e:
+ logger.error(f"A2A system error: {e}")
+ print(f"ā Error: {e}")
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/src/app/agents/deploy_real_agents.py b/src/app/agents/deploy_real_agents.py
index 73d8781..03a50c2 100644
--- a/src/app/agents/deploy_real_agents.py
+++ b/src/app/agents/deploy_real_agents.py
@@ -1,6 +1,6 @@
"""
-Deploy real agents to Azure AI Foundry using the AI Projects SDK.
-This creates 5 actual agents in the AI Foundry project.
+Deploy real agents to MSFT Foundry using the AI Projects SDK.
+This creates 6 specialized agents in the MSFT Foundry project with enhanced A2A protocol support.
"""
import os
import sys
@@ -95,6 +95,21 @@ def deploy_agents():
"Be efficient and confirm all cart operations clearly."
),
"model": "gpt-4o-mini"
+ },
+ {
+ "name": "Product Management Specialist",
+ "env_var": "product_management",
+ "instructions": (
+ "You are the Product Management Specialist for Zava, coordinating with specialized plugins for comprehensive product services. "
+ "Your expertise includes product catalog search and management, personalized recommendations through AI analysis, "
+ "market trend analysis and insights, product ranking and popularity metrics, and inventory coordination. "
+ "You work with ProductPlugin for catalog operations, MarketingPlugin for recommendations and trends, "
+ "and RankingPlugin for popularity analysis. Coordinate with other agents when queries involve design (interior_designer), "
+ "purchasing (cart_manager), loyalty benefits (customer_loyalty), or availability (inventory_agent). "
+ "Always provide accurate product information with specific names, prices, and availability. "
+ "Use A2A protocol patterns to ensure seamless handoffs to appropriate specialists."
+ ),
+ "model": "gpt-4o-mini"
}
]
diff --git a/src/app/agents/marketing_agent.py b/src/app/agents/marketing_agent.py
new file mode 100644
index 0000000..bbb2069
--- /dev/null
+++ b/src/app/agents/marketing_agent.py
@@ -0,0 +1,190 @@
+"""
+Marketing Agent - Specialized agent for product recommendations and marketing tasks
+
+This agent handles:
+- Product recommendations and personalization
+- Upselling and cross-selling strategies
+- Product description improvements
+- Marketing analysis and campaigns
+"""
+import asyncio
+import logging
+from typing import Dict, List, Optional
+from datetime import datetime
+
+from agent_framework import (
+ ChatAgent,
+ ChatMessage,
+ Executor,
+ Role,
+ WorkflowContext,
+ handler,
+)
+from agent_framework_azure_ai import AzureAIAgentClient
+from azure.identity.aio import DefaultAzureCredential
+
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+class MarketingAgentExecutor(Executor):
+ """
+ Marketing Agent specialized for recommendations, upselling, and marketing tasks
+ """
+
+ agent: ChatAgent
+
+ def __init__(self, agent: ChatAgent, id: str = "marketing_agent"):
+ self.agent = agent
+ super().__init__(id=id)
+
+ @handler
+ async def handle_marketing_request(
+ self, message: ChatMessage, ctx: WorkflowContext[list[ChatMessage], str]
+ ) -> None:
+ """Handle marketing-related requests"""
+ try:
+ query_text = message.text.lower()
+ messages: list[ChatMessage] = [message]
+
+ # Determine marketing task type
+ if any(keyword in query_text for keyword in ["recommend", "suggest", "advice"]):
+ marketing_context = await self._generate_recommendations(query_text)
+ elif any(keyword in query_text for keyword in ["upsell", "upgrade", "premium"]):
+ marketing_context = await self._generate_upselling_strategy(query_text)
+ elif any(keyword in query_text for keyword in ["cross-sell", "complement", "goes with"]):
+ marketing_context = await self._generate_cross_selling_strategy(query_text)
+ elif any(keyword in query_text for keyword in ["description", "improve", "enhance"]):
+ marketing_context = await self._improve_product_description(query_text)
+ else:
+ marketing_context = await self._general_marketing_analysis(query_text)
+
+ # Add marketing context to conversation
+ context_message = ChatMessage(
+ Role.ASSISTANT,
+ text=f"Marketing Analysis: {marketing_context}"
+ )
+ messages.append(context_message)
+
+ # Get agent response with marketing context
+ response = await self.agent.run(messages)
+ logger.info(f"Marketing Agent: {response.messages[-1].text}")
+
+ # Yield marketing response
+ await ctx.yield_output(response.messages[-1].text)
+
+ except Exception as e:
+ error_msg = f"Marketing Agent error: {str(e)}"
+ logger.error(error_msg)
+ await ctx.yield_output(error_msg)
+
+ async def _generate_recommendations(self, query: str) -> str:
+ """Generate personalized product recommendations"""
+ logger.info(f"Generating recommendations for: {query}")
+
+ # Simulated recommendation logic - would integrate with real data
+ recommendations = [
+ {"product": "Modern Sectional Sofa", "reason": "Perfect for large families", "confidence": 0.9},
+ {"product": "Coffee Table Set", "reason": "Complements modern furniture style", "confidence": 0.85},
+ {"product": "Floor Lamps", "reason": "Enhances room lighting", "confidence": 0.78}
+ ]
+
+ return f"Personalized recommendations generated: {len(recommendations)} products identified with high confidence scores"
+
+ async def _generate_upselling_strategy(self, query: str) -> str:
+ """Generate upselling strategies for products"""
+ logger.info(f"Generating upselling strategy for: {query}")
+
+ upsell_options = [
+ "Premium fabric upgrade (+$200) - Stain resistant and longer warranty",
+ "Extended warranty package (+$150) - 5-year coverage vs standard 2-year",
+ "Professional assembly service (+$99) - White glove delivery and setup"
+ ]
+
+ return f"Upselling opportunities identified: {len(upsell_options)} premium options available"
+
+ async def _generate_cross_selling_strategy(self, query: str) -> str:
+ """Generate cross-selling strategies"""
+ logger.info(f"Generating cross-selling strategy for: {query}")
+
+ cross_sell_items = [
+ "Accent pillows and throws - 25% off when bought together",
+ "Side tables to match your sofa style",
+ "Rugs that complement your color scheme"
+ ]
+
+ return f"Cross-selling opportunities: {len(cross_sell_items)} complementary items identified"
+
+ async def _improve_product_description(self, query: str) -> str:
+ """Improve product descriptions for better marketing"""
+ logger.info(f"Improving product description for: {query}")
+
+ improvements = [
+ "Added emotional appeal and lifestyle benefits",
+ "Highlighted unique selling propositions",
+ "Included technical specifications in customer-friendly language",
+ "Added social proof elements"
+ ]
+
+ return f"Product description improvements: {len(improvements)} enhancements applied"
+
+ async def _general_marketing_analysis(self, query: str) -> str:
+ """General marketing analysis"""
+ logger.info(f"Performing marketing analysis for: {query}")
+
+ return "Comprehensive marketing analysis completed - customer segments identified, positioning strategy developed"
+
+async def create_marketing_agent(
+ foundry_endpoint: str,
+ model_deployment: str
+) -> MarketingAgentExecutor:
+ """Create and configure the Marketing Agent"""
+
+ async with (
+ DefaultAzureCredential() as credential,
+ ChatAgent(
+ chat_client=AzureAIAgentClient(
+ project_endpoint=foundry_endpoint,
+ model_deployment_name=model_deployment,
+ async_credential=credential,
+ agent_name="MarketingAgent",
+ ),
+ instructions='''You are a Marketing Specialist for Zava, focused on product recommendations and sales optimization.
+
+Your expertise includes:
+- Personalized product recommendations based on customer preferences
+- Upselling strategies to premium products and services
+- Cross-selling complementary products and accessories
+- Product description enhancement for better customer appeal
+- Market analysis and customer segmentation
+
+MARKETING GUIDELINES:
+1. Always focus on customer value and satisfaction
+2. Provide specific, actionable recommendations with clear reasoning
+3. Use persuasive but honest marketing language
+4. Highlight unique selling propositions and competitive advantages
+5. Consider customer lifecycle and purchase history for personalization
+
+When handling requests:
+- Generate personalized recommendations with confidence scores
+- Suggest upselling opportunities that add genuine value
+- Identify cross-selling items that complement purchases
+- Improve product descriptions with emotional and technical appeals
+- Provide marketing insights based on current trends''',
+ ) as marketing_agent,
+ ):
+ return MarketingAgentExecutor(marketing_agent)
+
+if __name__ == "__main__":
+ async def test_marketing_agent():
+ import os
+ foundry_endpoint = os.getenv("FOUNDRY_ENDPOINT", "")
+ model_deployment = os.getenv("MODEL_DEPLOYMENT", "gpt-4o-mini")
+
+ if not foundry_endpoint:
+ print("Please set FOUNDRY_ENDPOINT environment variable")
+ return
+
+ marketing_executor = await create_marketing_agent(foundry_endpoint, model_deployment)
+ print("Marketing Agent created and ready for deployment!")
+
+ asyncio.run(test_marketing_agent())
\ No newline at end of file
diff --git a/src/app/agents/product_information_plugin.py b/src/app/agents/product_information_plugin.py
new file mode 100644
index 0000000..b91bb6b
--- /dev/null
+++ b/src/app/agents/product_information_plugin.py
@@ -0,0 +1,320 @@
+"""
+Product Information Plugin - Allows agents to look up product information from predefined list
+
+This plugin provides functionality for agents to access specific product information
+and perform particular tasks using factual data from a predefined product catalog.
+"""
+import logging
+from typing import Dict, List, Optional, Any
+from datetime import datetime
+
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+class ProductInformationPlugin:
+ """
+ Plugin that encapsulates product lookup functionality from a predefined list
+
+ This plugin allows agents to access factual product information rather than
+ generating responses based solely on instructions.
+ """
+
+ def __init__(self):
+ """Initialize with predefined product catalog"""
+ self.product_catalog = self._initialize_product_catalog()
+ logger.info(f"ProductInformationPlugin initialized with {len(self.product_catalog)} products")
+
+ def _initialize_product_catalog(self) -> List[Dict[str, Any]]:
+ """Initialize predefined product catalog with factual information"""
+
+ catalog = [
+ {
+ "id": "SOFA-001",
+ "name": "ModernComfort Sectional Sofa",
+ "category": "Living Room",
+ "subcategory": "Sofas",
+ "price": 1299.99,
+ "description": "3-piece sectional sofa with premium fabric upholstery",
+ "specifications": {
+ "dimensions": "108W x 85D x 36H inches",
+ "material": "High-grade fabric with foam cushioning",
+ "color_options": ["Charcoal Gray", "Navy Blue", "Beige"],
+ "weight_capacity": "300 lbs per seat",
+ "assembly_required": True
+ },
+ "availability": {
+ "in_stock": True,
+ "stock_level": 15,
+ "next_shipment": "2025-12-10",
+ "estimated_delivery": "3-5 business days"
+ },
+ "reviews": {
+ "average_rating": 4.3,
+ "total_reviews": 89,
+ "rating_breakdown": {"5_star": 45, "4_star": 28, "3_star": 12, "2_star": 3, "1_star": 1}
+ },
+ "features": ["Removable cushions", "Stain-resistant fabric", "2-year warranty"],
+ "tags": ["modern", "sectional", "comfortable", "family-friendly"]
+ },
+ {
+ "id": "TABLE-001",
+ "name": "Rustic Oak Coffee Table",
+ "category": "Living Room",
+ "subcategory": "Tables",
+ "price": 449.99,
+ "description": "Solid oak coffee table with rustic finish and storage drawer",
+ "specifications": {
+ "dimensions": "48W x 24D x 18H inches",
+ "material": "Solid oak wood with natural finish",
+ "color_options": ["Natural Oak", "Dark Walnut"],
+ "weight_capacity": "75 lbs",
+ "assembly_required": True
+ },
+ "availability": {
+ "in_stock": True,
+ "stock_level": 8,
+ "next_shipment": "2025-12-15",
+ "estimated_delivery": "5-7 business days"
+ },
+ "reviews": {
+ "average_rating": 4.7,
+ "total_reviews": 156,
+ "rating_breakdown": {"5_star": 98, "4_star": 42, "3_star": 12, "2_star": 3, "1_star": 1}
+ },
+ "features": ["Storage drawer", "Solid wood construction", "Rustic finish", "5-year warranty"],
+ "tags": ["rustic", "oak", "storage", "durable"]
+ },
+ {
+ "id": "CHAIR-001",
+ "name": "Ergonomic Office Chair Pro",
+ "category": "Office",
+ "subcategory": "Chairs",
+ "price": 329.99,
+ "description": "Professional ergonomic office chair with lumbar support",
+ "specifications": {
+ "dimensions": "26W x 26D x 40-44H inches (adjustable)",
+ "material": "Mesh back with cushioned seat",
+ "color_options": ["Black", "Gray", "Blue"],
+ "weight_capacity": "250 lbs",
+ "assembly_required": True
+ },
+ "availability": {
+ "in_stock": True,
+ "stock_level": 22,
+ "next_shipment": "2025-12-08",
+ "estimated_delivery": "2-4 business days"
+ },
+ "reviews": {
+ "average_rating": 4.5,
+ "total_reviews": 203,
+ "rating_breakdown": {"5_star": 122, "4_star": 58, "3_star": 18, "2_star": 4, "1_star": 1}
+ },
+ "features": ["Adjustable height", "Lumbar support", "360-degree swivel", "5-wheel base", "3-year warranty"],
+ "tags": ["ergonomic", "office", "adjustable", "professional"]
+ },
+ {
+ "id": "LAMP-001",
+ "name": "Contemporary Floor Lamp",
+ "category": "Lighting",
+ "subcategory": "Floor Lamps",
+ "price": 189.99,
+ "description": "Modern floor lamp with adjustable brightness and USB charging port",
+ "specifications": {
+ "dimensions": "12W x 12D x 58H inches",
+ "material": "Metal base with fabric shade",
+ "color_options": ["Brushed Steel", "Matte Black", "Antique Brass"],
+ "wattage": "60W LED compatible",
+ "assembly_required": False
+ },
+ "availability": {
+ "in_stock": True,
+ "stock_level": 31,
+ "next_shipment": "2025-12-12",
+ "estimated_delivery": "1-3 business days"
+ },
+ "reviews": {
+ "average_rating": 4.1,
+ "total_reviews": 67,
+ "rating_breakdown": {"5_star": 32, "4_star": 21, "3_star": 10, "2_star": 3, "1_star": 1}
+ },
+ "features": ["Adjustable brightness", "USB charging port", "Touch controls", "Energy efficient LED", "1-year warranty"],
+ "tags": ["contemporary", "adjustable", "USB", "LED"]
+ },
+ {
+ "id": "DESK-001",
+ "name": "Executive Standing Desk",
+ "category": "Office",
+ "subcategory": "Desks",
+ "price": 899.99,
+ "description": "Height-adjustable standing desk with memory settings and cable management",
+ "specifications": {
+ "dimensions": "60W x 30D x 28-48H inches (adjustable)",
+ "material": "Engineered wood top with steel frame",
+ "color_options": ["Espresso", "White Oak", "Gray"],
+ "weight_capacity": "200 lbs",
+ "assembly_required": True
+ },
+ "availability": {
+ "in_stock": False,
+ "stock_level": 0,
+ "next_shipment": "2025-12-20",
+ "estimated_delivery": "7-10 business days after restock"
+ },
+ "reviews": {
+ "average_rating": 4.6,
+ "total_reviews": 134,
+ "rating_breakdown": {"5_star": 89, "4_star": 32, "3_star": 9, "2_star": 3, "1_star": 1}
+ },
+ "features": ["Electric height adjustment", "Memory settings", "Cable management", "Anti-collision", "5-year warranty"],
+ "tags": ["standing", "adjustable", "executive", "ergonomic"]
+ }
+ ]
+
+ return catalog
+
+ def lookup_product_by_id(self, product_id: str) -> Optional[Dict[str, Any]]:
+ """Look up specific product by ID"""
+
+ for product in self.product_catalog:
+ if product["id"] == product_id:
+ logger.info(f"Product found: {product['name']} (ID: {product_id})")
+ return product
+
+ logger.warning(f"Product not found: {product_id}")
+ return None
+
+ def search_products_by_name(self, name_query: str) -> List[Dict[str, Any]]:
+ """Search products by name (partial match)"""
+
+ name_query = name_query.lower()
+ matching_products = []
+
+ for product in self.product_catalog:
+ if name_query in product["name"].lower():
+ matching_products.append(product)
+
+ logger.info(f"Name search for '{name_query}' found {len(matching_products)} products")
+ return matching_products
+
+ def filter_products_by_category(self, category: str, subcategory: str = None) -> List[Dict[str, Any]]:
+ """Filter products by category and optionally subcategory"""
+
+ filtered_products = []
+
+ for product in self.product_catalog:
+ if product["category"].lower() == category.lower():
+ if subcategory is None or product["subcategory"].lower() == subcategory.lower():
+ filtered_products.append(product)
+
+ logger.info(f"Category filter for '{category}' found {len(filtered_products)} products")
+ return filtered_products
+
+ def filter_products_by_price_range(self, min_price: float, max_price: float) -> List[Dict[str, Any]]:
+ """Filter products by price range"""
+
+ filtered_products = []
+
+ for product in self.product_catalog:
+ if min_price <= product["price"] <= max_price:
+ filtered_products.append(product)
+
+ logger.info(f"Price filter ${min_price}-${max_price} found {len(filtered_products)} products")
+ return filtered_products
+
+ def get_product_availability(self, product_id: str) -> Optional[Dict[str, Any]]:
+ """Get availability information for a specific product"""
+
+ product = self.lookup_product_by_id(product_id)
+ if product:
+ return product["availability"]
+
+ return None
+
+ def get_product_reviews_summary(self, product_id: str) -> Optional[Dict[str, Any]]:
+ """Get reviews summary for a specific product"""
+
+ product = self.lookup_product_by_id(product_id)
+ if product:
+ return product["reviews"]
+
+ return None
+
+ def search_products_by_tags(self, tags: List[str]) -> List[Dict[str, Any]]:
+ """Search products by tags"""
+
+ matching_products = []
+
+ for product in self.product_catalog:
+ product_tags = [tag.lower() for tag in product["tags"]]
+ if any(tag.lower() in product_tags for tag in tags):
+ matching_products.append(product)
+
+ logger.info(f"Tag search for {tags} found {len(matching_products)} products")
+ return matching_products
+
+ def get_all_categories(self) -> List[str]:
+ """Get list of all available categories"""
+
+ categories = list(set(product["category"] for product in self.product_catalog))
+ return sorted(categories)
+
+ def get_product_summary(self, product_id: str) -> Optional[str]:
+ """Get a formatted summary of product information"""
+
+ product = self.lookup_product_by_id(product_id)
+ if not product:
+ return None
+
+ availability_status = "In Stock" if product["availability"]["in_stock"] else "Out of Stock"
+
+ summary = f"""
+Product: {product['name']} ({product['id']})
+Category: {product['category']} > {product['subcategory']}
+Price: ${product['price']:.2f}
+Rating: {product['reviews']['average_rating']}/5 ({product['reviews']['total_reviews']} reviews)
+Availability: {availability_status}
+Key Features: {', '.join(product['features'])}
+Description: {product['description']}
+ """.strip()
+
+ return summary
+
+# Example usage and testing functions
+def demo_product_plugin():
+ """Demonstrate the Product Information Plugin functionality"""
+
+ plugin = ProductInformationPlugin()
+
+ print("=== Product Information Plugin Demo ===")
+
+ # Test product lookup by ID
+ print("\\n1. Lookup product by ID:")
+ sofa = plugin.lookup_product_by_id("SOFA-001")
+ if sofa:
+ print(f"Found: {sofa['name']} - ${sofa['price']}")
+
+ # Test search by name
+ print("\\n2. Search by name:")
+ chairs = plugin.search_products_by_name("chair")
+ for chair in chairs:
+ print(f" - {chair['name']}")
+
+ # Test filter by category
+ print("\\n3. Filter by category:")
+ office_products = plugin.filter_products_by_category("Office")
+ for product in office_products:
+ print(f" - {product['name']} (${product['price']})")
+
+ # Test price range filter
+ print("\\n4. Filter by price range ($200-$500):")
+ mid_range = plugin.filter_products_by_price_range(200, 500)
+ for product in mid_range:
+ print(f" - {product['name']} (${product['price']})")
+
+ # Test product summary
+ print("\\n5. Product summary:")
+ summary = plugin.get_product_summary("LAMP-001")
+ print(summary)
+
+if __name__ == "__main__":
+ demo_product_plugin()
\ No newline at end of file
diff --git a/src/app/agents/product_management_agent.py b/src/app/agents/product_management_agent.py
new file mode 100644
index 0000000..8206ea1
--- /dev/null
+++ b/src/app/agents/product_management_agent.py
@@ -0,0 +1,347 @@
+"""
+Product Management Agent using Microsoft Agent Framework
+
+This module implements a Product Management Agent that delegates tasks to
+specialized Marketing and Ranker agents, and uses the Product Information Plugin
+for factual product lookups from a predefined catalog.
+
+Key Features:
+- Delegates to Marketing Agent for recommendations, upselling, cross-selling
+- Delegates to Ranker Agent for comparisons, reviews, and rankings
+- Uses Product Information Plugin for factual product data
+- Coordinates multi-agent workflows using Agent Framework patterns
+"""
+import asyncio
+import logging
+import os
+from typing import Any, Dict, List, Optional
+from datetime import datetime
+
+from agent_framework import (
+ ChatAgent,
+ ChatMessage,
+ Executor,
+ Role,
+ WorkflowBuilder,
+ WorkflowContext,
+ WorkflowOutputEvent,
+ handler,
+)
+from agent_framework_azure_ai import AzureAIAgentClient
+from azure.identity.aio import DefaultAzureCredential
+
+from product_information_plugin import ProductInformationPlugin
+from marketing_agent import create_marketing_agent
+from ranker_agent import create_ranker_agent
+
+# Setup logging
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+class ProductManagerAgentExecutor(Executor):
+ """
+ Product Manager Agent that delegates to Marketing and Ranker agents as appropriate
+
+ This agent coordinates between specialized agents and uses factual data plugins
+ """
+
+ agent: ChatAgent
+ product_plugin: ProductInformationPlugin
+ marketing_agent: Optional[Any] = None
+ ranker_agent: Optional[Any] = None
+
+ def __init__(self, agent: ChatAgent, id: str = "product_manager"):
+ self.agent = agent
+
+ # Initialize Product Information Plugin for factual lookups
+ self.product_plugin = ProductInformationPlugin()
+
+ super().__init__(id=id)
+
+ def set_delegate_agents(self, marketing_agent: Any, ranker_agent: Any):
+ """Set the Marketing and Ranker agents for delegation"""
+ self.marketing_agent = marketing_agent
+ self.ranker_agent = ranker_agent
+ logger.info("Product Manager: Marketing and Ranker agents configured for delegation")
+
+ @handler
+ async def handle_product_request(
+ self, message: ChatMessage, ctx: WorkflowContext[list[ChatMessage], str]
+ ) -> None:
+ """Handle product requests and delegate to appropriate specialized agents"""
+ try:
+ query_text = message.text.lower()
+ messages: list[ChatMessage] = [message]
+
+ # Determine if delegation to specialized agents is needed
+ delegation_decision = await self._analyze_delegation_needs(query_text)
+
+ if delegation_decision["delegate_to"] == "marketing":
+ result = await self._delegate_to_marketing_agent(message, delegation_decision["reason"])
+
+ elif delegation_decision["delegate_to"] == "ranker":
+ result = await self._delegate_to_ranker_agent(message, delegation_decision["reason"])
+
+ elif delegation_decision["delegate_to"] == "product_lookup":
+ result = await self._handle_product_lookup(message)
+
+ else:
+ # Handle directly with Product Manager + Plugin data
+ result = await self._handle_direct_product_management(message)
+
+ # Product Manager coordinates and provides final response
+ coordination_msg = ChatMessage(
+ Role.ASSISTANT,
+ text=f"Product Manager coordination: {delegation_decision['reason']}. Result: {result}"
+ )
+ messages.append(coordination_msg)
+
+ # Get Product Manager's coordinated response
+ response = await self.agent.run(messages)
+ logger.info(f"Product Manager: {response.messages[-1].text}")
+
+ await ctx.yield_output(response.messages[-1].text)
+
+ except Exception as e:
+ error_msg = f"Product Manager error: {str(e)}"
+ logger.error(error_msg)
+ await ctx.yield_output(error_msg)
+
+ async def _analyze_delegation_needs(self, query: str) -> Dict[str, str]:
+ """Analyze whether to delegate to Marketing Agent, Ranker Agent, or handle directly"""
+
+ # Marketing Agent delegation criteria
+ if any(keyword in query for keyword in [
+ "recommend", "suggest", "upsell", "cross-sell", "marketing",
+ "promote", "campaign", "description", "improve"
+ ]):
+ return {
+ "delegate_to": "marketing",
+ "reason": "Marketing expertise required for recommendations/upselling/cross-selling"
+ }
+
+ # Ranker Agent delegation criteria
+ if any(keyword in query for keyword in [
+ "compare", "vs", "versus", "rank", "best", "top", "review",
+ "rating", "competitive", "analysis", "position"
+ ]):
+ return {
+ "delegate_to": "ranker",
+ "reason": "Ranking expertise required for comparisons/reviews/rankings"
+ }
+
+ # Product lookup criteria (factual information)
+ if any(keyword in query for keyword in [
+ "details", "specifications", "specs", "price", "availability",
+ "stock", "features", "dimensions", "warranty"
+ ]):
+ return {
+ "delegate_to": "product_lookup",
+ "reason": "Factual product information lookup required"
+ }
+
+ # Handle directly
+ return {
+ "delegate_to": "direct",
+ "reason": "General product management - handling directly with plugin support"
+ }
+
+ async def _delegate_to_marketing_agent(self, message: ChatMessage, reason: str) -> str:
+ """Delegate marketing-related tasks to Marketing Agent"""
+ logger.info(f"Product Manager delegating to Marketing Agent: {reason}")
+
+ if not self.marketing_agent:
+ return "Marketing Agent not available - handling basic recommendation logic"
+
+ try:
+ # Simulate delegation to Marketing Agent
+ # In a real implementation, this would invoke the Marketing Agent's workflow
+ marketing_context = f"Marketing delegation for: {message.text}"
+
+ # Use plugin data to enhance marketing response
+ if "furniture" in message.text.lower():
+ furniture_products = self.product_plugin.filter_products_by_category("Living Room")
+ marketing_context += f" | Available furniture products: {len(furniture_products)}"
+
+ return f"Marketing Agent completed: {marketing_context}"
+
+ except Exception as e:
+ return f"Marketing delegation error: {str(e)}"
+
+ async def _delegate_to_ranker_agent(self, message: ChatMessage, reason: str) -> str:
+ """Delegate ranking/comparison tasks to Ranker Agent"""
+ logger.info(f"Product Manager delegating to Ranker Agent: {reason}")
+
+ if not self.ranker_agent:
+ return "Ranker Agent not available - providing basic comparison"
+
+ try:
+ # Simulate delegation to Ranker Agent
+ ranking_context = f"Ranking delegation for: {message.text}"
+
+ # Use plugin data to enhance ranking response
+ if "sofa" in message.text.lower():
+ sofas = self.product_plugin.search_products_by_name("sofa")
+ ranking_context += f" | Found {len(sofas)} sofa products for comparison"
+
+ return f"Ranker Agent completed: {ranking_context}"
+
+ except Exception as e:
+ return f"Ranker delegation error: {str(e)}"
+
+ async def _handle_product_lookup(self, message: ChatMessage) -> str:
+ """Handle factual product information lookup using Plugin"""
+ logger.info("Product Manager using Product Information Plugin for factual lookup")
+
+ try:
+ query_text = message.text.lower()
+
+ # Extract product identifiers from query
+ if "sofa-001" in query_text or "sectional" in query_text:
+ product = self.product_plugin.lookup_product_by_id("SOFA-001")
+ if product:
+ return f"Product details: {product['name']} - ${product['price']} - {product['description']}"
+
+ # Search by category
+ if "office" in query_text:
+ products = self.product_plugin.filter_products_by_category("Office")
+ return f"Office products: {[p['name'] for p in products]}"
+
+ # General search
+ if "lamp" in query_text:
+ lamps = self.product_plugin.search_products_by_name("lamp")
+ return f"Available lamps: {[l['name'] for l in lamps]}"
+
+ # Default product catalog overview
+ categories = self.product_plugin.get_all_categories()
+ return f"Product catalog contains {len(self.product_plugin.product_catalog)} products across categories: {categories}"
+
+ except Exception as e:
+ return f"Product lookup error: {str(e)}"
+
+ async def _handle_direct_product_management(self, message: ChatMessage) -> str:
+ """Handle general product management tasks directly"""
+ logger.info("Product Manager handling request directly with plugin support")
+
+ try:
+ # Use plugin data to enhance response
+ total_products = len(self.product_plugin.product_catalog)
+ categories = self.product_plugin.get_all_categories()
+
+ return f"Product management analysis complete. Catalog: {total_products} products across {len(categories)} categories"
+
+ except Exception as e:
+ return f"Direct handling error: {str(e)}"
+
+async def create_product_manager_workflow(
+ foundry_endpoint: str,
+ model_deployment: str
+) -> WorkflowBuilder:
+ """
+ Create the Product Manager workflow with Marketing and Ranker agent delegation
+
+ Args:
+ foundry_endpoint: Microsoft Foundry project endpoint
+ model_deployment: Model deployment name in Foundry
+
+ Returns:
+ Configured WorkflowBuilder ready for execution
+ """
+
+ async with (
+ DefaultAzureCredential() as credential,
+ ChatAgent(
+ chat_client=AzureAIAgentClient(
+ project_endpoint=foundry_endpoint,
+ model_deployment_name=model_deployment,
+ async_credential=credential,
+ agent_name="ProductManagerAgent",
+ ),
+ instructions='''You are the Product Manager for Zava, coordinating specialized agents and product information.
+
+Your role is to:
+- Analyze customer requests and determine appropriate delegation strategy
+- Delegate marketing tasks (recommendations, upselling, cross-selling) to Marketing Agent
+- Delegate ranking tasks (comparisons, reviews, rankings) to Ranker Agent
+- Use Product Information Plugin for factual product data lookups
+- Coordinate responses from specialized agents and provide unified customer experience
+
+DELEGATION GUIDELINES:
+1. Marketing Agent: Use for recommendations, upselling, cross-selling, description improvements
+2. Ranker Agent: Use for product comparisons, reviews analysis, competitive rankings
+3. Product Plugin: Use for factual information like specifications, pricing, availability
+4. Direct handling: Use for general product management and coordination tasks
+
+COORDINATION APPROACH:
+- Always analyze the request type first
+- Choose the most appropriate specialist or handle directly
+- Integrate factual data from Product Information Plugin
+- Provide clear, helpful responses that leverage specialist expertise
+- Maintain consistent customer experience across all interactions''',
+ ) as product_manager_agent,
+ ):
+ # Create Product Manager executor
+ product_manager_executor = ProductManagerAgentExecutor(product_manager_agent)
+
+ # Create specialized agents for delegation
+ marketing_agent = await create_marketing_agent(foundry_endpoint, model_deployment)
+ ranker_agent = await create_ranker_agent(foundry_endpoint, model_deployment)
+
+ # Configure delegation
+ product_manager_executor.set_delegate_agents(marketing_agent, ranker_agent)
+
+ # Build workflow
+ workflow_builder = (
+ WorkflowBuilder()
+ .set_start_executor(product_manager_executor)
+ )
+
+ return workflow_builder
+
+# Example usage function
+async def main():
+ """Example of running the Product Manager with delegation"""
+
+ # Configuration - these would come from environment variables
+ foundry_endpoint = os.getenv("FOUNDRY_ENDPOINT", "")
+ model_deployment = os.getenv("MODEL_DEPLOYMENT", "gpt-4o-mini")
+
+ if not foundry_endpoint:
+ print("Please set FOUNDRY_ENDPOINT environment variable")
+ return
+
+ try:
+ workflow_builder = await create_product_manager_workflow(
+ foundry_endpoint,
+ model_deployment
+ )
+
+ workflow = workflow_builder.build()
+
+ # Test different types of requests to see delegation in action
+ test_requests = [
+ "Can you recommend some modern furniture for my living room?", # Should delegate to Marketing
+ "Compare the ModernComfort Sectional with other sofas", # Should delegate to Ranker
+ "What are the specifications of product SOFA-001?", # Should use Product Plugin
+ "Tell me about your product catalog" # Should handle directly
+ ]
+
+ print("Testing Product Manager with delegation...")
+
+ for i, request in enumerate(test_requests, 1):
+ print(f"\n--- Test {i}: {request} ---")
+
+ test_message = ChatMessage(Role.USER, text=request)
+
+ async for event in workflow.run_stream(test_message):
+ if isinstance(event, WorkflowOutputEvent):
+ print(f"Result: {event.data}")
+ break
+
+ print("\nProduct Manager delegation workflow completed successfully!")
+
+ except Exception as e:
+ logger.error(f"Error running Product Manager workflow: {e}")
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/src/app/agents/ranker_agent.py b/src/app/agents/ranker_agent.py
new file mode 100644
index 0000000..da67ccb
--- /dev/null
+++ b/src/app/agents/ranker_agent.py
@@ -0,0 +1,196 @@
+"""
+Ranker Agent - Specialized agent for product comparisons, reviews, and rankings
+
+This agent handles:
+- Product comparisons and feature analysis
+- Review processing and sentiment analysis
+- Product rankings by various criteria
+- Competitive analysis and positioning
+"""
+import asyncio
+import logging
+from typing import Dict, List, Optional
+from datetime import datetime
+
+from agent_framework import (
+ ChatAgent,
+ ChatMessage,
+ Executor,
+ Role,
+ WorkflowContext,
+ handler,
+)
+from agent_framework_azure_ai import AzureAIAgentClient
+from azure.identity.aio import DefaultAzureCredential
+
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+class RankerAgentExecutor(Executor):
+ """
+ Ranker Agent specialized for product comparisons, reviews, and rankings
+ """
+
+ agent: ChatAgent
+
+ def __init__(self, agent: ChatAgent, id: str = "ranker_agent"):
+ self.agent = agent
+ super().__init__(id=id)
+
+ @handler
+ async def handle_ranking_request(
+ self, message: ChatMessage, ctx: WorkflowContext[list[ChatMessage], str]
+ ) -> None:
+ """Handle ranking and comparison requests"""
+ try:
+ query_text = message.text.lower()
+ messages: list[ChatMessage] = [message]
+
+ # Determine ranking task type
+ if any(keyword in query_text for keyword in ["compare", "vs", "versus", "difference"]):
+ ranking_context = await self._perform_product_comparison(query_text)
+ elif any(keyword in query_text for keyword in ["review", "rating", "feedback"]):
+ ranking_context = await self._analyze_reviews(query_text)
+ elif any(keyword in query_text for keyword in ["rank", "best", "top", "popular"]):
+ ranking_context = await self._generate_product_rankings(query_text)
+ elif any(keyword in query_text for keyword in ["competitive", "competitor", "market position"]):
+ ranking_context = await self._analyze_competitive_position(query_text)
+ else:
+ ranking_context = await self._general_ranking_analysis(query_text)
+
+ # Add ranking context to conversation
+ context_message = ChatMessage(
+ Role.ASSISTANT,
+ text=f"Ranking Analysis: {ranking_context}"
+ )
+ messages.append(context_message)
+
+ # Get agent response with ranking context
+ response = await self.agent.run(messages)
+ logger.info(f"Ranker Agent: {response.messages[-1].text}")
+
+ # Yield ranking response
+ await ctx.yield_output(response.messages[-1].text)
+
+ except Exception as e:
+ error_msg = f"Ranker Agent error: {str(e)}"
+ logger.error(error_msg)
+ await ctx.yield_output(error_msg)
+
+ async def _perform_product_comparison(self, query: str) -> str:
+ """Compare products across multiple criteria"""
+ logger.info(f"Performing product comparison for: {query}")
+
+ # Simulated comparison logic - would integrate with real product data
+ comparison_criteria = [
+ {"criteria": "Price", "product_a_score": 8.5, "product_b_score": 7.2},
+ {"criteria": "Quality", "product_a_score": 9.1, "product_b_score": 8.8},
+ {"criteria": "Features", "product_a_score": 7.8, "product_b_score": 9.0},
+ {"criteria": "Customer Satisfaction", "product_a_score": 8.9, "product_b_score": 8.5}
+ ]
+
+ return f"Comprehensive product comparison completed: {len(comparison_criteria)} criteria analyzed with detailed scoring"
+
+ async def _analyze_reviews(self, query: str) -> str:
+ """Analyze product reviews and ratings"""
+ logger.info(f"Analyzing reviews for: {query}")
+
+ # Simulated review analysis - would integrate with review data
+ review_insights = {
+ "total_reviews": 247,
+ "average_rating": 4.3,
+ "sentiment_breakdown": {"positive": 78, "neutral": 15, "negative": 7},
+ "common_themes": ["comfortable", "durable", "good value", "stylish design"],
+ "improvement_areas": ["delivery time", "assembly instructions"]
+ }
+
+ return f"Review analysis complete: {review_insights['total_reviews']} reviews processed, {review_insights['average_rating']} avg rating, key themes identified"
+
+ async def _generate_product_rankings(self, query: str) -> str:
+ """Generate product rankings by specified criteria"""
+ logger.info(f"Generating rankings for: {query}")
+
+ # Simulated ranking logic
+ ranked_products = [
+ {"rank": 1, "product": "ModernComfort Sectional", "score": 9.2, "criteria": "Overall Value"},
+ {"rank": 2, "product": "StylePlus Sofa Set", "score": 8.8, "criteria": "Overall Value"},
+ {"rank": 3, "product": "CompactLiving Loveseat", "score": 8.5, "criteria": "Overall Value"},
+ {"rank": 4, "product": "PremiumCraft Recliner", "score": 8.1, "criteria": "Overall Value"}
+ ]
+
+ return f"Product rankings generated: Top {len(ranked_products)} products ranked by specified criteria with confidence scores"
+
+ async def _analyze_competitive_position(self, query: str) -> str:
+ """Analyze competitive positioning"""
+ logger.info(f"Analyzing competitive position for: {query}")
+
+ competitive_analysis = {
+ "market_position": "Strong - Top 3 in category",
+ "key_differentiators": ["Premium materials", "Extended warranty", "Local manufacturing"],
+ "competitive_advantages": ["Price-to-quality ratio", "Customer service", "Customization options"],
+ "areas_for_improvement": ["Online presence", "Product variety in premium segment"]
+ }
+
+ return f"Competitive analysis complete: Market position assessed, {len(competitive_analysis['key_differentiators'])} differentiators identified"
+
+ async def _general_ranking_analysis(self, query: str) -> str:
+ """General ranking and analysis"""
+ logger.info(f"Performing general ranking analysis for: {query}")
+
+ return "Comprehensive ranking analysis completed - products assessed across multiple dimensions"
+
+async def create_ranker_agent(
+ foundry_endpoint: str,
+ model_deployment: str
+) -> RankerAgentExecutor:
+ """Create and configure the Ranker Agent"""
+
+ async with (
+ DefaultAzureCredential() as credential,
+ ChatAgent(
+ chat_client=AzureAIAgentClient(
+ project_endpoint=foundry_endpoint,
+ model_deployment_name=model_deployment,
+ async_credential=credential,
+ agent_name="RankerAgent",
+ ),
+ instructions='''You are a Product Ranking and Comparison Specialist for Zava, focused on analytical evaluation.
+
+Your expertise includes:
+- Detailed product comparisons across multiple criteria
+- Review analysis and sentiment interpretation
+- Product ranking by popularity, quality, value, and customer satisfaction
+- Competitive analysis and market positioning
+- Data-driven recommendations based on objective metrics
+
+RANKING GUIDELINES:
+1. Use objective criteria and data-driven analysis
+2. Provide transparent scoring methodologies
+3. Consider multiple perspectives (price, quality, features, reviews)
+4. Highlight both strengths and weaknesses fairly
+5. Base rankings on verifiable metrics and customer feedback
+
+When handling requests:
+- Compare products using standardized criteria and scoring
+- Analyze reviews for patterns, sentiment, and actionable insights
+- Generate rankings with clear methodology and confidence levels
+- Provide competitive analysis with market positioning insights
+- Explain ranking rationale and methodology clearly''',
+ ) as ranker_agent,
+ ):
+ return RankerAgentExecutor(ranker_agent)
+
+if __name__ == "__main__":
+ async def test_ranker_agent():
+ import os
+ foundry_endpoint = os.getenv("FOUNDRY_ENDPOINT", "")
+ model_deployment = os.getenv("MODEL_DEPLOYMENT", "gpt-4o-mini")
+
+ if not foundry_endpoint:
+ print("Please set FOUNDRY_ENDPOINT environment variable")
+ return
+
+ ranker_executor = await create_ranker_agent(foundry_endpoint, model_deployment)
+ print("Ranker Agent created and ready for deployment!")
+
+ asyncio.run(test_ranker_agent())
\ No newline at end of file
diff --git a/src/app/agents/test_delegation_workflow.py b/src/app/agents/test_delegation_workflow.py
new file mode 100644
index 0000000..bc7eb5b
--- /dev/null
+++ b/src/app/agents/test_delegation_workflow.py
@@ -0,0 +1,250 @@
+"""
+Test script for Agent2Agent (A2A) delegation workflow
+Tests the coordination between Product Manager, Marketing Agent, and Ranker Agent
+with Product Information Plugin integration
+"""
+import asyncio
+import os
+import sys
+import logging
+from typing import List, Dict, Any
+
+# Add parent directory to sys.path for imports
+sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+from product_management_agent import create_product_manager_workflow
+from marketing_agent import create_marketing_agent
+from ranker_agent import create_ranker_agent
+from product_information_plugin import ProductInformationPlugin
+
+# Configure logging
+logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+logger = logging.getLogger(__name__)
+
+class DelegationTester:
+ """Test harness for verifying A2A delegation patterns"""
+
+ def __init__(self):
+ self.foundry_endpoint = os.getenv("AZURE_AI_PROJECT_ENDPOINT", "")
+ self.model_deployment = os.getenv("MODEL_DEPLOYMENT", "gpt-4o-mini")
+
+ # Test queries to verify different delegation patterns
+ self.test_queries = [
+ {
+ "query": "Can you recommend some modern furniture for my living room?",
+ "expected_delegation": "marketing",
+ "description": "Marketing task - recommendations and upselling"
+ },
+ {
+ "query": "Compare the ModernComfort Sectional with other sofas in your catalog",
+ "expected_delegation": "ranker",
+ "description": "Ranking task - product comparisons"
+ },
+ {
+ "query": "What are the specifications and price of product SOFA-001?",
+ "expected_delegation": "product_lookup",
+ "description": "Factual lookup - Product Information Plugin"
+ },
+ {
+ "query": "Tell me about your product catalog and available categories",
+ "expected_delegation": "direct",
+ "description": "General management - Product Manager direct handling"
+ },
+ {
+ "query": "I need help improving product descriptions for marketing campaigns",
+ "expected_delegation": "marketing",
+ "description": "Marketing expertise - description improvements"
+ },
+ {
+ "query": "Which dining table has the best customer reviews and ratings?",
+ "expected_delegation": "ranker",
+ "description": "Ranking expertise - review analysis and ratings"
+ }
+ ]
+
+ async def test_product_information_plugin(self):
+ """Test the Product Information Plugin directly"""
+ logger.info("=== Testing Product Information Plugin ===")
+
+ plugin = ProductInformationPlugin()
+
+ # Test product lookup
+ sofa = plugin.lookup_product_by_id("SOFA-001")
+ logger.info(f"Product SOFA-001: {sofa['name'] if sofa else 'Not found'}")
+
+ # Test category filtering
+ office_products = plugin.filter_products_by_category("Office")
+ logger.info(f"Office products: {len(office_products)} items")
+
+ # Test search
+ lamp_results = plugin.search_products_by_name("lamp")
+ logger.info(f"Lamp search results: {len(lamp_results)} items")
+
+ # Test categories
+ categories = plugin.get_all_categories()
+ logger.info(f"Available categories: {categories}")
+
+ return True
+
+ async def test_agent_creation(self):
+ """Test individual agent creation"""
+ logger.info("=== Testing Individual Agent Creation ===")
+
+ if not self.foundry_endpoint:
+ logger.warning("No FOUNDRY_ENDPOINT configured - using mock agents")
+ return False
+
+ try:
+ # Test Marketing Agent creation
+ logger.info("Creating Marketing Agent...")
+ marketing_agent = await create_marketing_agent(self.foundry_endpoint, self.model_deployment)
+ logger.info("ā Marketing Agent created successfully")
+
+ # Test Ranker Agent creation
+ logger.info("Creating Ranker Agent...")
+ ranker_agent = await create_ranker_agent(self.foundry_endpoint, self.model_deployment)
+ logger.info("ā Ranker Agent created successfully")
+
+ return True
+
+ except Exception as e:
+ logger.error(f"Agent creation failed: {e}")
+ return False
+
+ async def test_delegation_analysis(self):
+ """Test the delegation decision logic"""
+ logger.info("=== Testing Delegation Analysis ===")
+
+ # Import the executor for testing delegation logic
+ from product_management_agent import ProductManagerAgentExecutor
+ from agent_framework import ChatAgent
+
+ # Create mock agent for testing
+ class MockChatAgent:
+ async def run(self, messages):
+ class MockResponse:
+ def __init__(self):
+ from agent_framework import ChatMessage, Role
+ self.messages = [ChatMessage(Role.ASSISTANT, text="Mock response")]
+ return MockResponse()
+
+ executor = ProductManagerAgentExecutor(MockChatAgent())
+
+ # Test delegation analysis for each query
+ for test_case in self.test_queries:
+ decision = await executor._analyze_delegation_needs(test_case["query"].lower())
+
+ expected = test_case["expected_delegation"]
+ actual = decision["delegate_to"]
+
+ status = "ā" if actual == expected else "ā"
+ logger.info(f"{status} Query: '{test_case['query'][:50]}...'")
+ logger.info(f" Expected: {expected} | Actual: {actual}")
+ logger.info(f" Reason: {decision['reason']}")
+ logger.info("")
+
+ return True
+
+ async def test_full_workflow(self):
+ """Test the complete Product Manager workflow if Foundry is available"""
+ logger.info("=== Testing Full Workflow ===")
+
+ if not self.foundry_endpoint:
+ logger.warning("No FOUNDRY_ENDPOINT - skipping full workflow test")
+ return False
+
+ try:
+ # Create the workflow
+ workflow_builder = await create_product_manager_workflow(
+ self.foundry_endpoint,
+ self.model_deployment
+ )
+
+ workflow = workflow_builder.build()
+ logger.info("ā Workflow created successfully")
+
+ # Test with one sample query
+ from agent_framework import ChatMessage, Role, WorkflowOutputEvent
+
+ test_message = ChatMessage(
+ Role.USER,
+ text="What are the specifications of your sectional sofas?"
+ )
+
+ logger.info("Running sample workflow...")
+
+ async for event in workflow.run_stream(test_message):
+ if isinstance(event, WorkflowOutputEvent):
+ logger.info(f"Workflow result: {event.data[:100]}...")
+ break
+
+ logger.info("ā Full workflow test completed")
+ return True
+
+ except Exception as e:
+ logger.error(f"Full workflow test failed: {e}")
+ return False
+
+ async def run_all_tests(self):
+ """Run all delegation tests"""
+ logger.info("Starting A2A Delegation Workflow Tests")
+ logger.info("=" * 60)
+
+ results = {}
+
+ # Test 1: Product Information Plugin
+ try:
+ results["plugin"] = await self.test_product_information_plugin()
+ except Exception as e:
+ logger.error(f"Plugin test failed: {e}")
+ results["plugin"] = False
+
+ # Test 2: Agent Creation (if Foundry available)
+ try:
+ results["agents"] = await self.test_agent_creation()
+ except Exception as e:
+ logger.error(f"Agent creation test failed: {e}")
+ results["agents"] = False
+
+ # Test 3: Delegation Logic
+ try:
+ results["delegation"] = await self.test_delegation_analysis()
+ except Exception as e:
+ logger.error(f"Delegation test failed: {e}")
+ results["delegation"] = False
+
+ # Test 4: Full Workflow (if Foundry available)
+ try:
+ results["workflow"] = await self.test_full_workflow()
+ except Exception as e:
+ logger.error(f"Full workflow test failed: {e}")
+ results["workflow"] = False
+
+ # Summary
+ logger.info("=" * 60)
+ logger.info("TEST RESULTS SUMMARY")
+ logger.info("=" * 60)
+
+ for test_name, passed in results.items():
+ status = "PASS" if passed else "FAIL"
+ logger.info(f"{test_name.upper()}: {status}")
+
+ total_tests = len(results)
+ passed_tests = sum(results.values())
+
+ logger.info(f"\nOverall: {passed_tests}/{total_tests} tests passed")
+
+ if passed_tests == total_tests:
+ logger.info("š All delegation tests PASSED! A2A workflow is ready.")
+ else:
+ logger.info("ā ļø Some tests failed. Check configuration and dependencies.")
+
+ return results
+
+async def main():
+ """Main test runner"""
+ tester = DelegationTester()
+ await tester.run_all_tests()
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/src/app/tools/singleAgentExample.py b/src/app/tools/singleAgentExample.py
index 22ffc85..d670212 100644
--- a/src/app/tools/singleAgentExample.py
+++ b/src/app/tools/singleAgentExample.py
@@ -29,7 +29,7 @@
client = None
def get_client():
- """Lazily initialize and return the Azure AI Foundry client"""
+ """Lazily initialize and return the MSFT Foundry client"""
global client
if client is None:
# Graceful fallback if endpoint or key missing
@@ -64,7 +64,7 @@ def generate_response(text_input):
# Get initialized client
client = get_client()
- # Prepare the messages for Azure AI Foundry
+ # Prepare the messages for MSFT Foundry
messages = [
{
"role": "system",
@@ -104,7 +104,7 @@ def generate_response(text_input):
}
]
- # Call Azure AI Foundry chat API
+ # Call MSFT Foundry chat API
response = client.complete(
model=deployment,
messages=messages,
diff --git a/src/requirements.txt b/src/requirements.txt
index 46e7428..0d1638d 100644
--- a/src/requirements.txt
+++ b/src/requirements.txt
@@ -16,3 +16,6 @@ python-multipart==0.0.12
orjson==3.10.7
pydantic==2.10.4
Pillow>=10.4.0
+
+# Microsoft Agent Framework for A2A Protocol (Preview)
+agent-framework-azure-ai --pre
diff --git a/terraform-infrastructure/main.tf b/terraform-infrastructure/main.tf
index 6f3dcd2..62062ac 100644
--- a/terraform-infrastructure/main.tf
+++ b/terraform-infrastructure/main.tf
@@ -57,7 +57,7 @@ resource "azurerm_cosmosdb_account" "cosmos" {
geo_location {
location = var.location
failover_priority = 0
- zone_redundant = false # Disable zone redundancy to avoid high demand issues
+ zone_redundant = false # Disable zone redundancy to avoid high demand issues for demo
}
free_tier_enabled = false
analytical_storage_enabled = false
@@ -340,14 +340,14 @@ resource "azurerm_linux_web_app" "app" {
gpt_api_key = "@Microsoft.KeyVault(SecretUri=${azurerm_key_vault.kv.vault_uri}secrets/ai-foundry-key)"
gpt_api_version = "2024-12-01-preview"
- # Azure AI Foundry Configuration
+ # MSFT Foundry Configuration
AZURE_AI_FOUNDRY_ENDPOINT = "https://${local.ai_foundry_name}.cognitiveservices.azure.com/"
AZURE_AI_PROJECT_NAME = local.ai_project_name
AZURE_AI_PROJECT_ENDPOINT = "https://${local.ai_foundry_name}.cognitiveservices.azure.com/"
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME = "gpt-4o-mini"
AZURE_AI_FOUNDRY_API_KEY = "@Microsoft.KeyVault(SecretUri=${azurerm_key_vault.kv.vault_uri}secrets/ai-foundry-key)"
- # Azure OpenAI Configuration
+ # MSFT Foundry OpenAI Configuration
AZURE_OPENAI_CHAT_DEPLOYMENT = "gpt-4o-mini"
AZURE_OPENAI_EMBEDDING_DEPLOYMENT = "text-embedding-3-small"
AZURE_OPENAI_IMAGE_DEPLOYMENT = "dall-e-3"
@@ -812,7 +812,7 @@ resource "azurerm_role_assignment" "search_project_contributor" {
principal_type = "ServicePrincipal"
}
-# Storage account permissions for Azure AI Foundry project
+# Storage account permissions for MSFT Foundry project
resource "azurerm_role_assignment" "storage_blob_data_contributor_user" {
scope = azapi_resource.storage.id
role_definition_id = "/subscriptions/${data.azurerm_client_config.current.subscription_id}/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe"
@@ -997,7 +997,7 @@ data "azapi_resource_action" "ai_foundry_keys" {
depends_on = [azapi_resource.ai_foundry]
}
-# Connect resources to Azure AI Foundry project using ARM templates
+# Connect resources to MSFT Foundry project using ARM templates
resource "azapi_resource" "storage_connection" {
count = var.enable_ai_automation ? 1 : 0
@@ -1188,7 +1188,7 @@ resource "null_resource" "create_env_file" {
New-Item -ItemType Directory -Path "../src" -Force
}
- # Get Azure AI Foundry endpoint and fix domain for Agents API
+ # Get MSFT Foundry endpoint and fix domain for Agents API
$rawAiFoundryEndpoint = az cognitiveservices account show `
--resource-group "${azurerm_resource_group.rg.name}" `
--name "${local.ai_foundry_name}" `
@@ -1350,7 +1350,7 @@ CUSTOMER_ID=CUST001
} else {
Write-Host " - Models: gpt-4o-mini, text-embedding-3-small (phi-4 not available)"
}
- Write-Host " - Azure AI Foundry: ${local.ai_foundry_name}"
+ Write-Host " - MSFT Foundry: ${local.ai_foundry_name}"
Write-Host " - Azure AI Project: ${local.ai_project_name}"
Write-Host " - Cosmos DB: ${local.cosmos_account_name}"
Write-Host " - Search Service: ${local.search_service_name}"
@@ -1619,7 +1619,7 @@ resource "null_resource" "deploy_multi_agents" {
Write-Host "Using Agents API endpoint: $agentEndpoint"
# Deploy agents using Python script
- Write-Host "Deploying 5 agents to Azure AI Foundry..."
+ Write-Host "Deploying 6 agents to MSFT Foundry..."
$agentScriptPath = Join-Path (Split-Path $PWD.Path -Parent) "src\app\agents\deploy_real_agents.py"
if (!(Test-Path $agentScriptPath)) {
@@ -1776,7 +1776,7 @@ resource "null_resource" "verify_real_agents" {
Write-Host "Running agent verification..."
& $pythonCmd $quickVerifyScript
if ($LASTEXITCODE -eq 0) {
- Write-Host "[SUCCESS] All agents verified in Azure AI Foundry"
+ Write-Host "[SUCCESS] All agents verified in MSFT Foundry"
} else {
Write-Host "WARNING: Agent verification reported issues (check output above)"
}
@@ -1847,7 +1847,7 @@ resource "null_resource" "deploy_chat_app" {
# Build container directly in ACR (no local Docker needed)
Write-Host "Building chat application container in Azure Container Registry..."
- Write-Host "This includes the Azure AI Foundry SDK with corrected endpoint configuration"
+ Write-Host "This includes the MSFT Foundry SDK with corrected endpoint configuration"
Write-Host "Build time: approximately 2-3 minutes..."
Write-Host ""
@@ -1905,7 +1905,7 @@ resource "null_resource" "deploy_chat_app" {
--query "properties.endpoint" `
--output tsv
- # Get Azure AI Foundry access key
+ # Get MSFT Foundry access key
$aiFoundryKey = az cognitiveservices account keys list `
--resource-group ${azurerm_resource_group.rg.name} `
--name ${local.ai_foundry_name} `
@@ -1954,7 +1954,7 @@ resource "null_resource" "deploy_chat_app" {
Write-Host " [HEALTH] Health Check: https://${local.web_app_name}.azurewebsites.net/health"
Write-Host ""
Write-Host " [OK] Container: ${local.registry_name}.azurecr.io/zava-chat-app:latest"
- Write-Host " [OK] SDK: azure-ai-inference (Azure AI Foundry)"
+ Write-Host " [OK] SDK: azure-ai-inference (MSFT Foundry)"
Write-Host " [OK] Model: gpt-4o-mini"
Write-Host " [OK] Endpoint: .services.ai.azure.com/models (auto-converted)"
Write-Host ""
@@ -2634,4 +2634,7 @@ resource "null_resource" "post_deploy_health" {
}
}
+# Enaganeced Product Management Agent Resources
+
+
diff --git a/terraform-infrastructure/outputs.tf b/terraform-infrastructure/outputs.tf
index 2684827..f6dac68 100644
--- a/terraform-infrastructure/outputs.tf
+++ b/terraform-infrastructure/outputs.tf
@@ -30,12 +30,12 @@ output "application_url" {
output "ai_foundry_name" {
value = local.ai_foundry_name
- description = "Azure AI Foundry account name"
+ description = "MSFT Foundry account name"
}
output "ai_project_name" {
value = local.ai_project_name
- description = "Azure AI Foundry project name"
+ description = "MSFT Foundry project name"
}
output "resource_group_name" {
@@ -61,7 +61,7 @@ output "cosmos_db_name" {
output "ai_foundry_endpoint" {
value = "https://${local.ai_foundry_name}.cognitiveservices.azure.com/"
- description = "Azure AI Foundry endpoint URL"
+ description = "MSFT Foundry endpoint URL"
}
# Real agent IDs & statuses (external data source from agents_state.json)