Add Gmail and Google Calendar integration

Implements on-demand Google tools (not adapter) for email and calendar access via OAuth2.

Features:
- OAuth2 user consent flow with automatic token refresh
- 3 Gmail tools: send_email, read_emails, get_email
- 3 Calendar tools: read_calendar, create_calendar_event, search_calendar
- Lazy loading pattern for Google clients
- Secure token storage with file permissions
- Browser-based setup: python bot_runner.py --setup-google

Architecture:
- Tools-only approach (zero API calls when not in use)
- User-initiated actions only (no continuous polling)
- MIME message creation for emails with threading support
- HTML to text conversion for email parsing
- ISO 8601 timestamp handling for calendar events

Files added:
- google_tools/oauth_manager.py: OAuth2 flow and token management
- google_tools/gmail_client.py: Gmail API wrapper
- google_tools/calendar_client.py: Calendar API wrapper
- google_tools/utils.py: Email/MIME helpers
- config/scheduled_tasks.yaml: Example scheduled tasks config

Files modified:
- tools.py: Added 6 Google tool handlers with lazy initialization
- bot_runner.py: Added --setup-google command for OAuth authorization
- requirements.txt: Added Google API dependencies
- .gitignore: Added google_credentials.yaml and google_oauth_token.json

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 10:29:28 -07:00
parent 8afff96bb5
commit dc14baf426
10 changed files with 1555 additions and 1 deletions

View File

@@ -26,6 +26,7 @@ from adapters.slack.adapter import SlackAdapter
from adapters.telegram.adapter import TelegramAdapter
from agent import Agent
from config.config_loader import ConfigLoader
from google_tools.oauth_manager import GoogleOAuthManager
from scheduled_tasks import TaskScheduler
# Adapter class registry mapping platform names to their classes
@@ -195,6 +196,16 @@ def main() -> None:
action="store_true",
help="Run health check",
)
parser.add_argument(
"--setup-google",
action="store_true",
help="Set up Google OAuth for Gmail/Calendar integration",
)
parser.add_argument(
"--manual",
action="store_true",
help="Use manual OAuth code entry (for headless servers)",
)
args = parser.parse_args()
@@ -209,6 +220,32 @@ def main() -> None:
print("3. Run: python bot_runner.py")
return
if args.setup_google:
print("=" * 60)
print("Google OAuth Setup")
print("=" * 60)
print()
oauth_manager = GoogleOAuthManager()
if oauth_manager.is_authorized():
print("✓ Already authorized!")
print(f"✓ Tokens found at {oauth_manager.token_file}")
print("\nTo re-authorize, delete the token file and run this command again.")
return
success = oauth_manager.run_oauth_flow(manual=args.manual)
if success:
print("You can now use Gmail and Calendar tools!")
print("\nTest it:")
print(" Via Telegram: \"What's on my calendar?\"")
print(" Via Telegram: \"Send an email to john@example.com\"")
else:
print("\nSetup failed. Please check:")
print("1. config/google_credentials.yaml exists with valid client_id/client_secret")
print("2. You authorized the app in your browser")
print("3. No firewall blocking localhost:8080")
return
runner = BotRunner(config_file=args.config)
if args.health: