Oliver-ai-bot_2.0/backend/app/tools/microsoft/graph_base.py
Vadym Samoilenko 7511c27750 Phase 2: Tool calling + Microsoft 365 integrations
- Add tool framework (BaseTool ABC, ToolRegistry, ToolContext/ToolResult)
- Implement agentic loop in LLMFactory.stream_with_tools() with max_rounds and timeout
- Add 9 Microsoft Graph tools: Calendar (3), Mail (3), Teams (1), Planner (2)
- Add Graph Token Manager with Fernet encryption and auto-refresh
- Add consent flow endpoints (start/callback/status/revoke)
- Add admin tool management endpoints (list/toggle)
- Add SSE tool events (tool_start, tool_result, tool_error) in chat endpoint
- Frontend: ToolCallCard component, tool call tracking in chat store
- Frontend: Admin Integrations tab with per-tool enable/disable
- Frontend: Consent banner and M365 connect flow
- Migration 008: tool_definitions, user_graph_tokens, message_tool_calls tables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:26:53 +00:00

52 lines
1.4 KiB
Python

"""
Base class for Microsoft Graph API tools
"""
import logging
from typing import Any, Dict, Optional
import httpx
from app.tools.base import BaseTool, ToolContext, ToolResult
logger = logging.getLogger(__name__)
GRAPH_BASE_URL = "https://graph.microsoft.com/v1.0"
class GraphBaseTool(BaseTool):
"""Base class providing Graph API request helpers"""
@property
def requires_graph_consent(self) -> bool:
return True
async def _graph_request(
self,
method: str,
path: str,
context: ToolContext,
params: Optional[Dict[str, Any]] = None,
json_body: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
"""
Make an authenticated request to the Microsoft Graph API.
Raises httpx.HTTPStatusError on non-2xx responses.
"""
url = f"{GRAPH_BASE_URL}{path}"
headers = {
"Authorization": f"Bearer {context.graph_token}",
"Content-Type": "application/json",
}
async with httpx.AsyncClient(timeout=25.0) as client:
response = await client.request(
method=method,
url=url,
headers=headers,
params=params,
json=json_body,
)
response.raise_for_status()
if response.status_code == 204:
return {}
return response.json()