Files
clawrity/channels/teams_handler.py
T
2026-05-04 22:00:38 +05:30

125 lines
4.1 KiB
Python

"""
Clawrity — Microsoft Teams Handler (STUB)
Skeleton implementation of the Bot Framework adapter for Microsoft Teams.
Proves the multi-channel architecture is real — any channel handler produces
NormalisedMessage via ProtocolAdapter, so the entire pipeline works unchanged.
# TODO: Wire up Azure Bot credentials when ready for Teams demo.
# Required: MICROSOFT_APP_ID, MICROSOFT_APP_PASSWORD
# Package: botbuilder-core, botbuilder-schema
Status: NOT IMPLEMENTED — Slack is the priority for development.
"""
import logging
from typing import Dict, Optional
from channels.protocol_adapter import ProtocolAdapter, NormalisedMessage
from config.client_loader import ClientConfig
logger = logging.getLogger(__name__)
class TeamsHandler:
"""
Microsoft Teams bot handler stub.
Architecture:
Teams Activity → ProtocolAdapter.normalise_teams() → Orchestrator → Response
The same pipeline used by Slack — zero business logic in this layer.
"""
def __init__(
self,
protocol_adapter: ProtocolAdapter,
client_configs: Dict[str, ClientConfig],
orchestrator, # agents.orchestrator.Orchestrator
):
self.adapter = protocol_adapter
self.client_configs = client_configs
self.orchestrator = orchestrator
# TODO: Wire up Azure Bot credentials from .env
# self.app_id = settings.microsoft_app_id
# self.app_password = settings.microsoft_app_password
async def handle_activity(self, activity: dict) -> str:
"""
Process an incoming Teams Bot Framework activity.
# TODO: Implement when ready for Teams demo.
Expected flow:
1. Receive activity from Bot Framework webhook
2. Normalise via ProtocolAdapter.normalise_teams(activity)
3. Route to Orchestrator.process(message, client_config)
4. Return response via Bot Framework turn context
Args:
activity: Raw Bot Framework activity dict
Returns:
Response text to send back to Teams
"""
# --- Stub implementation ---
message = self.adapter.normalise_teams(activity)
client_config = self.client_configs.get(message.client_id)
if not client_config:
return f"No configuration found for client: {message.client_id}"
result = await self.orchestrator.process(message, client_config)
return result["response"]
def setup_routes(self, app):
"""
Register Teams webhook endpoint with FastAPI.
# TODO: Implement Bot Framework adapter integration.
Expected endpoint:
POST /api/teams/messages → Bot Framework webhook
Requires:
- botbuilder-core package
- BotFrameworkAdapter with app_id + app_password
- CloudAdapter or BotFrameworkHttpClient
"""
logger.info(
"Teams handler stub loaded. "
"To enable Teams: install botbuilder-core, set Azure Bot credentials."
)
# TODO: Uncomment and implement when ready
#
# from botbuilder.core import (
# BotFrameworkAdapter,
# BotFrameworkAdapterSettings,
# TurnContext,
# )
#
# settings = BotFrameworkAdapterSettings(
# app_id=self.app_id,
# app_password=self.app_password,
# )
# adapter = BotFrameworkAdapter(settings)
#
# @app.post("/api/teams/messages")
# async def teams_webhook(request: Request):
# body = await request.json()
# activity = Activity().deserialize(body)
# auth_header = request.headers.get("Authorization", "")
# response = await adapter.process_activity(
# activity, auth_header, self._on_turn
# )
# return response
#
# async def _on_turn(turn_context: TurnContext):
# activity = turn_context.activity
# response = await self.handle_activity(activity.__dict__)
# await turn_context.send_activity(response)
pass