Deploy CommunityRAPP to Microsoft Teams and Microsoft 365 Copilot using Power Platform.
Power Platform integration enables you to deploy your AI assistant to:
| Feature | Standalone Mode | Power Platform Mode |
|---|---|---|
| Access Point | REST API, Web UI | Teams, M365 Copilot, Web |
| User Authentication | Function key | Azure AD/SSO |
| User Context | Manual (GUID) | Automatic (Office 365 profile) |
| Conversation UI | Custom HTML | Teams native UI |
| Analytics | Application Insights | Power Platform Analytics + App Insights |
| Deployment | Azure only | Azure + Microsoft 365 |
Perfect for Power Platform when:
Stick with Standalone when:
Per User:
Organization:
Permissions Needed:
Azure Resources:
Check you have everything:
# Check if you have Power Automate Premium
# 1. Go to https://flow.microsoft.com
# 2. Click "My flows" β "New flow"
# 3. If you see "Automated cloud flow" and premium connectors, you're good!
# Get your Azure Function details
# You'll need these from your deployment:
# - Function URL: https://YOUR-APP.azurewebsites.net/api/businessinsightbot_function
# - Function Key: (from Azure Portal β Function App β Functions β businessinsightbot_function β Function Keys)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β User Interface Layer β
β Microsoft Teams β M365 Copilot β Power Apps β Web UI β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ
β Conversation Layer β
β Copilot Studio β
β β’ Natural Language Processing β
β β’ Dialog Management β
β β’ Intent Recognition β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ
β Integration Layer β
β Power Automate β
β β’ User Context Enrichment (Office 365 profile) β
β β’ Data Transformation β
β β’ Error Handling & Retry Logic β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ
β Processing Layer β
β Azure Function App β
β β’ Agent Selection & Routing β
β β’ Memory Management β
β β’ Azure OpenAI Integration β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ
β Agent Layer β
β Memory β Email β Calendar β Custom β GitConflict β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ
β Data Layer β
β Azure Storage β Azure OpenAI β Microsoft Graph β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Request Flow:
1. User sends message in Teams/M365 Copilot
β
2. Copilot Studio processes natural language
β
3. Triggers Power Automate flow
β
4. Power Automate enriches with Office 365 user data
β - User name
β - Email address
β - Department
β - Job title
β
5. HTTP POST to Azure Function
{
"user_input": "User's message",
"conversation_history": [...],
"user_guid": "office365-user-id",
"user_context": {
"email": "user@company.com",
"name": "John Doe",
"department": "Engineering"
}
}
β
6. Azure Function processes request
β - Loads user memory
β - Routes to appropriate agents
β - Calls Azure OpenAI
β
7. Returns response to Power Automate
β
8. Power Automate formats for Copilot Studio
β
9. Copilot Studio displays in Teams/M365 Copilot
Option 1: From GitHub Releases (Recommended)
Copilot365_PowerPlatform_Solution.zipOption 2: Create Manually
If no solution package is available, follow the manual setup in Phase 2-4.
Copilot365-Backend-ConnectorName: user_message |
Type: Text |
Name: conversation_id |
Type: Text (optional) |
https://YOUR-FUNCTION-APP.azurewebsites.net/api/businessinsightbot_function{
"Content-Type": "application/json",
"x-functions-key": "YOUR_FUNCTION_KEY_HERE"
}
{
"user_input": @{triggerBody()?['user_message']},
"conversation_history": [],
"user_guid": "@{outputs('Get_my_profile_(V2)')?['body/id']}",
"user_context": {
"email": "@{outputs('Get_my_profile_(V2)')?['body/mail']}",
"name": "@{outputs('Get_my_profile_(V2)')?['body/displayName']}",
"department": "@{outputs('Get_my_profile_(V2)')?['body/department']}",
"jobTitle": "@{outputs('Get_my_profile_(V2)')?['body/jobTitle']}"
}
}
body('HTTP'){
"assistant_response": "Hello! How can I help you?",
"voice_response": "Hello!",
"agent_logs": "Session initialized",
"user_guid": "abc-123"
}
Name: bot_response |
Value: body('Parse_JSON')?['assistant_response'] |
Name: voice_response |
Value: body('Parse_JSON')?['voice_response'] |
body('HTTP')?['status'] equals faileduser_message: "Hello"Copilot 365 AgentMain Assistant TopicCopilot365-Backend-Connector)user_message β Activity.Text (userβs message)BotResponse β bot_responseVoiceResponse β voice_response{x:BotResponse}Step 1: Publish Copilot
Step 2: Configure Teams Channel
Step 3: Add to Teams
Step 4: Add to Teams App Store
Step 1: Create Declarative Agent
declarativeAgent.json):{
"$schema": "https://developer.microsoft.com/json-schemas/copilot/declarative-agent/v1.0/schema.json",
"version": "v1.0",
"id": "contoso-rapp-agent",
"name": "Copilot 365 Agent",
"description": "Enterprise AI assistant with persistent memory and custom agents",
"instructions": "You are an enterprise AI assistant. Help users with their questions using available agents and tools.",
"conversation_starters": [
{
"title": "Help me get started",
"text": "What can you help me with?"
},
{
"title": "Draft an email",
"text": "Help me draft a professional email"
},
{
"title": "Search my documents",
"text": "Find documents about project planning"
}
],
"actions": [
{
"id": "contoso-rapp-backend",
"type": "powerPlatform",
"powerPlatformFlowId": "YOUR_FLOW_ID_HERE"
}
],
"capabilities": {
"conversationHistory": true,
"webSearch": false
}
}
Step 2: Package as Teams App
Copilot365Agent/
βββ manifest.json
βββ declarativeAgent.json
βββ color.png (192x192)
βββ outline.png (32x32)
manifest.json:
{
"$schema": "https://developer.microsoft.com/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
"manifestVersion": "1.16",
"id": "YOUR-UNIQUE-GUID",
"version": "1.0.0",
"developer": {
"name": "Your Organization",
"websiteUrl": "https://yourcompany.com",
"privacyUrl": "https://yourcompany.com/privacy",
"termsOfUseUrl": "https://yourcompany.com/terms"
},
"name": {
"short": "Copilot 365 Agent",
"full": "Copilot 365 Enterprise AI Assistant"
},
"description": {
"short": "AI assistant with persistent memory",
"full": "Enterprise AI assistant built on Azure with GPT-4, featuring persistent memory, custom agents, and Microsoft 365 integration."
},
"icons": {
"color": "color.png",
"outline": "outline.png"
},
"copilotAgents": {
"declarativeAgents": [
{
"id": "contoso-rapp-agent",
"file": "declarativeAgent.json"
}
]
}
}
Step 3: Deploy to M365 Copilot
Step 4: Test in M365 Copilot
Update your agents to use Office 365 user context:
from agents.basic_agent import BasicAgent
class PersonalizedAgent(BasicAgent):
def __init__(self):
self.name = 'Personalized'
self.metadata = {
"name": self.name,
"description": "Provides personalized assistance using user context",
"parameters": {
"type": "object",
"properties": {
"user_context": {
"type": "object",
"description": "Office 365 user profile information",
"properties": {
"email": {"type": "string"},
"name": {"type": "string"},
"department": {"type": "string"},
"jobTitle": {"type": "string"}
}
},
"query": {
"type": "string",
"description": "User's request"
}
},
"required": ["query"]
}
}
super().__init__(self.name, self.metadata)
def perform(self, user_context=None, query="", **kwargs):
"""
Perform personalized assistance using user context.
Args:
user_context (dict): Office 365 user profile
query (str): User's request
"""
if user_context:
name = user_context.get('name', 'User')
email = user_context.get('email', 'unknown')
department = user_context.get('department', 'Unknown')
job_title = user_context.get('jobTitle', 'Unknown')
# Personalize response based on department
if 'Engineering' in department:
return f"Hi {name}, as an engineer, I can help you with technical documentation, code reviews, and development workflows. What do you need?"
elif 'Sales' in department:
return f"Hello {name}, I can assist with CRM data, customer insights, and sales reports. How can I help?"
else:
return f"Hello {name} from {department}, how can I assist you today?"
else:
return "Hello! How can I assist you?"
from utils.azure_file_storage import AzureFileStorageManager
class UserPreferencesAgent(BasicAgent):
def __init__(self):
self.name = 'UserPreferences'
self.storage = AzureFileStorageManager()
# ... metadata setup ...
def perform(self, user_guid="", action="get", preference_key="", preference_value="", **kwargs):
"""
Manage user-specific preferences.
Args:
user_guid (str): Office 365 user ID
action (str): 'get' or 'set'
preference_key (str): Preference name
preference_value (str): Preference value (for 'set')
"""
file_name = f"user_preferences_{user_guid}.json"
if action == "set":
# Load existing preferences
preferences = self.storage.read_file("user_data", file_name)
if not preferences:
preferences = {}
else:
import json
preferences = json.loads(preferences)
# Update preference
preferences[preference_key] = preference_value
# Save back
import json
self.storage.write_file("user_data", file_name, json.dumps(preferences))
return f"Preference '{preference_key}' saved successfully."
elif action == "get":
preferences = self.storage.read_file("user_data", file_name)
if preferences:
import json
prefs = json.loads(preferences)
return prefs.get(preference_key, "Preference not found")
return "No preferences found"
For dev/test/prod environments:
Development Environment:
{
"user_input": "test message",
"conversation_history": [],
"user_guid": "dev-test-user",
"environment": "development",
"azure_function_url": "https://dev-contoso-rapp.azurewebsites.net/api/businessinsightbot_function"
}
Production Environment:
{
"user_input": "production message",
"conversation_history": [],
"user_guid": "@{outputs('Get_my_profile_(V2)')?['body/id']}",
"environment": "production",
"azure_function_url": "https://prod-contoso-rapp.azurewebsites.net/api/businessinsightbot_function"
}
Create separate Power Automate flows for each environment.
For scenarios requiring additional authentication:
To maintain conversation history across messages:
In Power Automate:
conversationHistory[]{
"role": "user",
"content": "@{triggerBody()?['user_message']}"
}
{
"conversation_history": @{variables('conversationHistory')},
...
}
Protect your backend from abuse:
In Power Automate:
In Azure Function:
from datetime import datetime, timedelta
import json
def check_rate_limit(user_guid, storage_manager):
"""Check if user has exceeded rate limit."""
rate_limit_file = f"rate_limit_{user_guid}.json"
# Get current rate limit data
data = storage_manager.read_file("rate_limits", rate_limit_file)
if data:
rate_data = json.loads(data)
last_reset = datetime.fromisoformat(rate_data['last_reset'])
# Reset if hour has passed
if datetime.now() - last_reset > timedelta(hours=1):
rate_data = {'count': 0, 'last_reset': datetime.now().isoformat()}
# Check limit
if rate_data['count'] >= 100: # 100 requests per hour
return False, "Rate limit exceeded. Try again later."
rate_data['count'] += 1
else:
rate_data = {'count': 1, 'last_reset': datetime.now().isoformat()}
# Save updated count
storage_manager.write_file("rate_limits", rate_limit_file, json.dumps(rate_data))
return True, ""
View Flow Runs:
Debug Failed Runs:
| Issue | Cause | Solution |
|---|---|---|
| βUnauthorizedβ (401) | Invalid function key | Regenerate key in Azure Portal β Function App β Function Keys |
| βBad Requestβ (400) | Invalid request body format | Check JSON structure matches expected schema |
| βTimeoutβ (500) | Function execution > 230s | Optimize agents, enable streaming, or increase timeout |
| User context not passed | Office 365 connector permissions | Re-authenticate Office 365 Users connector |
| Copilot doesnβt trigger | Missing trigger phrases | Add more variations in Copilot Studio topics |
| Response not displaying | Incorrect variable mapping | Verify output variables match in flow and copilot |
| Slow responses | Cold start latency | Enable βAlways Onβ in Function App (requires Basic or higher plan) |
In Power Automate:
Compose_UserInput: @{triggerBody()?['user_message']}
Compose_HTTPResponse: @{body('HTTP')}
In Azure Function:
Update local.settings.json and Azure configuration:
{
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "python",
"LOGGING_LEVEL": "DEBUG"
}
}
Check logs in Azure Portal β Function App β Logs (or Application Insights).
1. Reduce Cold Starts:
2. Cache Responses:
import hashlib
from functools import lru_cache
@lru_cache(maxsize=100)
def get_cached_response(user_input_hash):
# Return cached response if available
pass
def generate_response(user_input):
input_hash = hashlib.md5(user_input.encode()).hexdigest()
cached = get_cached_response(input_hash)
if cached:
return cached
# Generate new response...
3. Parallel Agent Execution:
import asyncio
async def execute_agents_parallel(agents, user_input):
tasks = [agent.perform_async(input=user_input) for agent in agents]
results = await asyncio.gather(*tasks)
return results
Azure Components: | Service | Plan | Cost | |βββ|ββ|ββ| | Function App | Consumption | ~$0 (1M free executions/month) | | Storage | Standard | ~$5/month | | Azure OpenAI | Pay-per-use | ~$0.01-0.03 per 1K tokens | | Application Insights | Basic | ~$2-5/month |
Power Platform Components: | Service | Plan | Cost per User/Month | |βββ|ββ|βββββββ| | Power Automate | Premium | ~$15 | | Copilot Studio | Included in Premium | $0 | | Microsoft 365 Copilot | Optional | ~$30 |
Total Estimates:
For 10 users with moderate usage (50 conversations/day):
For 100 users with moderate usage:
Cost Optimization Tips:
DO:
DONβT:
Implementation:
# Rotate function key
az functionapp keys renew \
--name YOUR_FUNCTION_APP \
--resource-group YOUR_RESOURCE_GROUP \
--key-type functionKeys \
--key-name default
Enable DLP policies in Power Platform Admin Center:
Copilot365-DLPEnable in Power Platform:
Enable in Azure:
FunctionAppLogs
| where TimeGenerated > ago(24h)
| where Message contains "businessinsightbot_function"
| project TimeGenerated, Message, Level
Restrict Function App Access:
Use Private Endpoints: For enhanced security, deploy Function App with private endpoints:
az functionapp vnet-integration add \
--name YOUR_FUNCTION_APP \
--resource-group YOUR_RESOURCE_GROUP \
--vnet YOUR_VNET \
--subnet YOUR_SUBNET
In Copilot Studio:
Example Privacy Message:
π Welcome to Copilot 365 Agent!
Before we start, please note:
β’ Your conversations are processed using Azure OpenAI
β’ We store conversation history to improve responses
β’ Your Office 365 profile (name, email) is used for personalization
β’ All data is encrypted and complies with Microsoft's privacy standards
By using this assistant, you agree to our Privacy Policy: [link]
Ready to get started? Ask me anything!
Microsoft Purview Integration:
Regular Security Reviews:
Now that you have Power Platform integration set up:
Ready to build amazing experiences? π Start integrating with Power Platform today!