Intelligent Agentic AI-Powered Calendar and Task Management Backend
A unified Python service combining Google Calendar integration with advanced task management, powered by LangGraph workflow automation and Groq LLM.
- Overview
- Features
- Quick Start
- Architecture
- API Documentation
- Configuration
- Components
- Development
- Testing
- Troubleshooting
This service provides a FastAPI backend that combines:
- Calendar Agent: Natural language Google Calendar management using LangGraph workflows
- Task Agent: Intelligent task parsing with priority detection, effort estimation, and deadline extraction
- Constraint Analysis: Identifies scheduling constraints (hard/soft) and detects conflicts
- Clarification System: Autonomous decision-making for when to ask users for clarification
- Observability: Langfuse integration for monitoring and debugging
- Framework: FastAPI + Uvicorn
- AI/LLM: Groq (Llama 3.1 8B Instant)
- Workflow: LangGraph + LangChain
- Calendar API: Google Calendar API v3
- Observability: Langfuse
- Language: Python 3.10+
- Python 3.10 or higher
- Google Cloud account (for Calendar API)
- Groq API key (for LLM)
- Navigate to Directory:
cd calender-agent-service- Create Virtual Environment:
# Windows
python -m venv venv
venv\Scripts\activate
# Linux/Mac
python3 -m venv venv
source venv/bin/activate- Install Dependencies:
pip install -r requirements.txt- Configure Environment - Create
.envfile:
# Required: Groq API Key
GROQ_API_KEY=your-groq-api-key-here
# Server Configuration
PORT=8000
HOST=0.0.0.0
# User Preferences - Dynamic Timing
USER_TIMEZONE=America/New_York
WORK_START=9
WORK_END=17
LUNCH_HOUR=13
DEADLINE_HOUR=17
# Langfuse Observability
LANGFUSE_ENABLED=true
LANGFUSE_PUBLIC_KEY=your-public-key
LANGFUSE_SECRET_KEY=your-secret-key
LANGFUSE_HOST=http://localhost:3000Option 1: Python Command
python app_langgraph.pyOption 2: Batch File (Windows)
start_backend.batOption 3: Shell Script (Linux/Mac)
chmod +x start.sh
./start.shThe server will start on http://localhost:8000
Verify it's running:
curl http://localhost:8000/health-
Natural Language Understanding: Parse plain English task descriptions
-
Priority Detection: Automatically identifies task urgency
- Keywords: "urgent", "asap", "important" β High priority
- Keywords: "low", "whenever" β Low priority
- Default: Medium priority
-
Category Classification: Smart categorization
- Work, Personal, Health, Finance, Shopping, Family, Education, Travel, Entertainment, General
-
Effort Estimation: Predicts time required
- "quick task" β 15-30 mins
- "meeting" β 30 mins - 1 hour
- "all day" β 4-8 hours
- Supports: quick, short, medium, long, half-day, all-day
-
Deadline Extraction: Natural language date parsing
- "tomorrow" β Next day
- "by Friday" β End of Friday
- "next week" β Following week
- "in 3 days" β 3 days from now
- Dynamic timezone support (respects USER_TIMEZONE)
-
Smart Title Cleaning: Removes task-related prefixes
- "TODO: Fix bug" β "Fix bug"
- "urgent: call client" β "call client"
- Task Memory: In-memory task storage with context tracking
- Task Summarization: Get overview of all tasks with effort totals
- Bulk Operations: Process multiple tasks simultaneously
- Preprocessing: Cleans and reformats user input
- Intent Classification: Determines if query is calendar-related or general
- Request Parsing: Extracts calendar operations and event details
- Constraint Identification: Analyzes scheduling constraints
- Hard constraints: Must be satisfied (e.g., "must be after 2pm")
- Soft constraints: Preferences (e.g., "preferably in the morning")
- Conflict Detection: Checks for scheduling conflicts
- Clarification Agent: Decides when to ask for user clarification
- Human-in-the-Loop: Optional approval before execution
- Execution: Performs calendar operations via Google Calendar API
- Response Formatting: Provides user-friendly responses
- List Calendars: View all available calendars
- Create Calendar: Create new calendars
- List Events: View events from specific or all calendars
- Create Events: Add events with natural language
- Single events
- Recurring events
- All-day events
- Events with location
- Reschedule Events: Intelligent event rescheduling with safety mechanisms
- RETRIEVEβDELETEβCREATE workflow: Safe rescheduling with rollback support
- Natural language time parsing: "from 1pm to 2pm", "to 3pm", "move to tomorrow"
- Rule-based fast-path: Deterministic parsing for common patterns
- Context-aware: Uses conversation history to identify events
- Automatic rollback: If creation fails, restores the deleted event
- Time range interpretation: Correctly handles "from X to Y" as new time slot
- Update Events: Modify existing event details
- Delete Events: Remove events by name or ID
- Delete Calendars: Remove entire calendars
- Conflict Detection: Automatic overlap detection with alternative suggestions
- Smart Scheduling: AI-powered optimal time slot finder
- Reschedule Intelligence:
- Safe RETRIEVEβDELETEβCREATE Workflow: Three-step process ensures data integrity
- Automatic Rollback: If new event creation fails, original event is restored
- Rule-Based Parser: Fast deterministic parsing for "from X to Y" patterns
- LLM Fallback: Complex reschedule requests handled by LLM when rules don't match
- Context Resolution: Identifies events from conversation ("reschedule it", "move that meeting")
- Time Range Disambiguation: "from 1pm to 2pm" correctly interpreted as new 1-2pm slot, not end time
- Dynamic Timing Configuration: User-specific timezone and work hours
- Time References: Understands contextual time (morning, afternoon, evening)
- Sequential Date Parsing: Handles "tomorrow, the next day, the day after that"
- Declarative Statements: Recognizes "I have a meeting at 3pm" as create command
- Confidence Scoring: Measures certainty of parsed intent (0.0-1.0)
- Context Awareness: Maintains conversation history via thread_id
- Memory Persistence: LangGraph MemorySaver for stateful conversations
- Self-Reflection Node: Validates execution success after operations
- Debug Information: Detailed parsing and matching debug data
Identifies and classifies scheduling constraints:
- Hard Constraints: Must be satisfied
- Specific time requirements
- Date restrictions
- Duration requirements
- Soft Constraints: Preferences
- Preferred time ranges
- Ideal durations
- Optional conditions
Autonomously decides when to ask for clarification:
- Confidence Scoring: Calculates certainty (0.0-1.0)
- Smart Thresholds:
- High confidence (β₯0.7): Proceed automatically
- Medium confidence (0.5-0.7): May ask for clarification
- Low confidence (<0.5): Always clarify
- Context-Aware: Considers existing schedule and constraints
- Reduces Friction: Only asks when truly necessary
Langfuse Integration:
- Trace all LLM calls
- Monitor API performance
- Debug agent behavior
- View token usage
- Track error rates
http://localhost:8000
Service information
Response:
{
"service": "Calendar + Task Agent",
"version": "2.0.0",
"status": "running"
}Health check
Response:
{
"status": "healthy",
"service": "calendar-task-agent",
"timestamp": "2025-12-29T10:30:00Z"
}Process natural language task with full parsing
Request Body:
{
"message": "urgent: finish quarterly report by Friday afternoon",
"user_id": "user-123"
}Response:
{
"status": "success",
"parsed_task": {
"id": "task_abc123",
"title": "finish quarterly report",
"priority": "high",
"category": "Work",
"effort_estimate": "medium",
"estimated_time": "1-2 hours",
"deadline": "2025-12-29T17:00:00Z",
"created_at": "2025-12-29T10:30:00Z"
},
"conversational_response": "Got it! I've scheduled **'finish quarterly report'** as a high priority task.",
"context": {
"active_tasks": 12,
"completed_today": 3
}
}Quick task parsing without saving
Request Body:
{
"text": "quick task: call dentist tomorrow morning"
}Response:
{
"title": "call dentist",
"priority": "medium",
"category": "Personal",
"estimated_time": "15-30 mins",
"deadline": "2025-12-30T09:00:00Z"
}Get summary of all tasks
Request Body:
{
"existing_tasks": [...]
}Response:
{
"summary": "π Task Summary\n\nπ Overview:\n β’ Total Tasks: 2\n β’ High Priority: 1",
"statistics": {
"total": 2,
"high_priority": 1,
"total_hours": 2.5
}
}Natural language calendar management with full rescheduling support
Request Body:
{
"user_message": "Schedule team meeting tomorrow at 2pm for 1 hour",
"thread_id": "optional-conversation-id",
"messages": [],
"calendar_id": "primary"
}Response:
{
"response": "β
Event created successfully!\n\nπ
Team meeting\nπ December 30, 2025 at 2:00 PM - 3:00 PM",
"state": {
"intent": "calendar",
"action": "create_event",
"confidence_score": 0.95,
"conflicts": []
},
"thread_id": "abc-123"
}Reschedule Examples:
Example 1: Time range reschedule
{
"user_message": "Reschedule my dentist appointment from 1pm to 2pm today"
}Response:
{
"response": "β
Event rescheduled successfully!\n\nπ
dentist appointment\nπ Moved to December 30, 2025 at 1:00 PM - 2:00 PM\n\nπ± Check your Google Calendar!",
"state": {
"action": "reschedule_event",
"event_to_update": "dentist appointment",
"updated_events": [...]
}
}Example 2: Simple time change
{
"user_message": "Move the team meeting to 3pm"
}Example 3: Date and time change
{
"user_message": "Reschedule my workout to tomorrow at 6am"
}Clarification Response:
{
"response": "β I need clarification:\n\nWhat is the event title?",
"state": {
"needs_clarification": true,
"confidence_score": 0.45
}
}Conflict Response:
{
"response": "β οΈ Scheduling Conflict Detected\n\nπ‘ Suggested alternatives:\nβ’ 3:00 PM - 4:00 PM",
"state": {
"requires_approval": true,
"conflicts": [...],
"suggested_times": [...]
}
}List all calendars
Response:
{
"calendars": [
{
"id": "primary",
"name": "My Calendar",
"accessRole": "owner",
"primary": true
}
],
"count": 1
}Get events from calendar
Query Parameters:
calendar_id(required)max_capacity(optional, default: 200)
Response:
{
"events": [...],
"count": 5,
"calendar_id": "primary"
}Get events from all calendars
Response:
{
"events": [...],
"total_events": 10,
"calendars_checked": 3
}Run the test suite:
python test_integrated.pyExpected output:
β
Task agent imported successfully
β
Task parsing works
β
'quick: test' β 15-30 mins
β
'2 hour coding' β 1-2 hours
β
Calendar graph imported successfully
ALL TESTS PASSED! β
# Input: "quick task: call dentist"
# Output:
{
"title": "call dentist",
"priority": "medium",
"estimated_time": "15-30 mins",
"category": "General"
}
# Input: "urgent: fix production bug (all day)"
# Output:
{
"title": "fix production bug",
"priority": "high",
"estimated_time": "4-8 hours",
"category": "Work"
}
# Input: "short meeting tomorrow at 2pm"
# Output:
{
"title": "short meeting",
"priority": "medium",
"estimated_time": "30 mins - 1 hour",
"scheduled_time": "14:00",
"deadline": "2025-12-30T17:00:00"
}Example 1: Time Range Reschedule
# User says: "Reschedule my dentist appointment from 1pm to 2pm today"
# What happens internally:
# 1. Rule-based parser detects "from X to Y" pattern
# 2. Extracts: start=13:00, end=14:00
# 3. Searches for "dentist appointment" in calendar
# 4. RETRIEVE: Gets existing event details
# 5. DELETE: Removes old event
# 6. CREATE: Adds new event at 1pm-2pm
# 7. If CREATE fails β Rollback: Restores deleted event
# Response:
{
"response": "β
Event rescheduled successfully!\n\nπ
dentist appointment\nπ Moved to December 30, 2025 at 1:00 PM - 2:00 PM",
"state": {
"action": "reschedule_event",
"updated_events": [...]
}
}Example 2: Context-Aware Reschedule
# Conversation flow:
User: "Schedule team meeting tomorrow at 2pm"
Agent: "β
Event created: team meeting at 2pm"
User: "Actually, move it to 3pm"
# Agent uses context to identify "it" = "team meeting"
# Reschedules to 3pm automaticallyExample 3: Date Change
# User says: "Reschedule my workout to next Monday at 6am"
# Process:
# 1. Searches for "workout" event
# 2. Calculates next Monday's date
# 3. RETRIEVE existing event
# 4. DELETE old event
# 5. CREATE new event on Monday at 6amExample 4: Declarative Statements
# User says: "I have a meeting today from 3pm to 4pm"
# Agent recognizes this as CREATE, not RESCHEDULE
# Creates new event (doesn't try to find existing event to move)Example 5: Multiple Sequential Events
# User says: "I need to prepare a presentation. schedule 2 hours of research tomorrow,
# 1 hour for slide creation the next day, 30 minutes for rehearsal the day after that."
# Creates 3 events:
# 1. Research: Tomorrow (Dec 31)
# 2. Slide creation: Day after tomorrow (Jan 1)
# 3. Rehearsal: 3 days from now (Jan 2)| Keywords | Estimated Time |
|---|---|
| quick, fast, brief | 15-30 mins |
| short, 30 min, 1 hour | 30 mins - 1 hour |
| 2 hours, afternoon | 1-2 hours |
| 4 hours, half day | 2-4 hours |
| all day, full day | 4-8 hours |
# Parse a task
curl -X POST http://localhost:8000/api/task-agent/parse \
-H "Content-Type: application/json" \
-d '{"message": "urgent: fix bug tomorrow", "existing_tasks": []}'
# Response:
{
"success": true,
"parsed_task": {
"title": "fix bug",
"priority": "high",
"category": "Work",
"estimated_time": "1-2 hours",
"deadline": "2025-12-30T17:00:00"
},
"conversational_response": "Got it! I've scheduled **'fix bug'** as a high priority task. β±οΈ Estimated time: **1-2 hours**.",
"context": "Active tasks: 0, Completed today: 0, High priority: 0"
}βββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FastAPI Application β
β ββββββββββββββββββββ βββββββββββββββββββββββ β
β β Task Agent β β Calendar Agent β β
β β Endpoints β β Endpoints β β
β ββββββββββ¬ββββββββββ ββββββββββββ¬βββββββββββ β
β β β β
β ββββββββββΌββββββββββ βββββββββββΌβββββββββββββ β
β β Task Parser β β LangGraph Workflow β β
β β - Priority β β - Preprocess β β
β β - Category β β - Router β β
β β - Effort Est. β β - Parser β β
β β - Deadline β β - Constraint Agent β β
β ββββββββββββββββββββ β - Clarification β β
β β - Conflict Check β β
β β - Executor β β
β βββββββββββ¬βββββββββββββ β
ββββββββββββββββββββββββββββββββββββΌβββββββββββββββββ
β
ββββββββββββΌβββββββββββ
β Google Calendar β
β API v3 β
ββββββββββββββββββββββ
START
β
βΌ
[Preprocess]
β
βΌ
[Router] ββββββββββββββΊ [General Response] βββΊ END
β
β (calendar intent)
βΌ
[Parse Calendar Request]
β
ββββΊ [Constraint Agent]
β β
β βΌ
β [Clarification Agent]
β β
β ββββΊ (needs clarification) βββΊ END
β β
β βΌ
β [Conflict Detection]
β β
β βΌ
β [Approval Check] βββΊ [Wait for Approval] βββΊ (recursive)
β β
β βΌ
β [Execute Workflow]
β β
βΌ βΌ
[Format Response] βββΊ END
calender-agent-service/
βββ app_langgraph.py # Main FastAPI + Task Agent
βββ graph.py # LangGraph workflow definition
βββ nodes.py # Workflow node implementations (2400+ lines)
β # Includes: preprocess, parse, reschedule logic,
β # planner, conflict detection, execution
βββ state.py # State type definitions (CalendarState)
βββ calendar_tools.py # Google Calendar API wrapper functions
βββ constraint_agent.py # Constraint analysis and classification
βββ clarification_agent.py # Autonomous clarification logic
βββ google_apis.py # Google OAuth and API client setup
βββ langfuse_integration.py # Observability and tracing hooks
βββ requirements.txt # Python dependencies
βββ .env # Configuration (create this)
βββ client_secret.json # Google OAuth (download from GCP)
βββ token_calender_v3.pickle # Auth token (auto-generated)
βββ start_backend.bat # Windows startup script
βββ start.sh # Linux/Mac startup script
βββ README.md # Documentation
Reschedule Workflow (nodes.py ~lines 1050-1170):
# STEP 1: RETRIEVE - Search for existing event
events = search_events(calendar_id, event_to_update, max_results=5)
# STEP 2: DELETE - Remove old event (store backup)
deleted_result = delete_calendar_event(calendar_id, event_id)
backup_event = existing_event.copy()
# STEP 3: CREATE - Add new event
new_result = insert_calendar_event(calendar_id, new_event_data)
# ROLLBACK: If creation fails, restore deleted event
if not new_result.get("success"):
insert_calendar_event(calendar_id, backup_event)Rule-Based Parser (nodes.py ~lines 380-430):
# Fast deterministic parsing for common patterns
# Pattern: "from 1pm to 2pm"
m = re.search(r"from\s+(\d{1,2}(?::\d{2})?\s*(?:am|pm))\s+to\s+(\d{1,2}(?::\d{2})?\s*(?:am|pm))", user_msg)
# Only triggers for actual reschedule commands, not create statements
is_reschedule_command = any(word in user_msg for word in ["reschedule", "move", "change", "shift", "update"])-
Task Agent Classes:
TaskPriority- Enum for priority levelsParsedTask- Parsed task data structureTaskMemory- Task context and historyTaskParser- NLP parsing logicTaskAgent- Main task processing
-
FastAPI Application:
- Task agent endpoints
- Calendar agent endpoints
- CORS middleware
- Health checks
-
LangGraph Integration:
- Calendar graph for complex workflows
- State management
- Memory persistence
Create .env file in project root:
# ============================================================================
# REQUIRED
# ============================================================================
# Groq API Key (for LLM)
GROQ_API_KEY=your_groq_api_key_here
# ============================================================================
# SERVER CONFIGURATION
# ============================================================================
# Port number (default: 8000)
PORT=8000
# Host binding (default: 0.0.0.0)
HOST=0.0.0.0
# ============================================================================
# USER PREFERENCES - Dynamic Timing
# ============================================================================
# User timezone (default: UTC)
# Examples: America/New_York, Europe/London, Asia/Tokyo
USER_TIMEZONE=America/New_York
# Work hours start (default: 9 AM)
WORK_START=9
# Work hours end (default: 5 PM)
WORK_END=17
# Lunch hour (default: 1 PM)
LUNCH_HOUR=13
# Default deadline hour when only date specified (default: 5 PM)
DEADLINE_HOUR=17
# ============================================================================
# LANGFUSE OBSERVABILITY (Optional)
# ============================================================================
# Enable Langfuse tracing (default: false)
LANGFUSE_ENABLED=true
# Langfuse credentials (get from https://cloud.langfuse.com/)
LANGFUSE_PUBLIC_KEY=pk-lf-xxx
LANGFUSE_SECRET_KEY=sk-lf-xxx
LANGFUSE_HOST=https://cloud.langfuse.comThe service adapts to your work schedule and timezone:
Time References:
morning: UsesWORK_START(e.g., 9 AM)after lunch: UsesLUNCH_HOUR(e.g., 1 PM)end of day: UsesWORK_END(e.g., 5 PM)tomorrow eod: Tomorrow atDEADLINE_HOUR(e.g., 5 PM)
Example:
USER_TIMEZONE=Europe/London
WORK_START=8
WORK_END=18
LUNCH_HOUR=12With this:
- "Schedule meeting in the morning" β 8:00 AM London time
- "Task due tomorrow eod" β Tomorrow 6:00 PM London time
-
Create Google Cloud Project:
- Visit https://console.cloud.google.com/
- Create new project
- Enable Google Calendar API
-
Create OAuth Credentials:
- Go to APIs & Services β Credentials
- Create OAuth 2.0 Client ID
- Application type: Desktop app
- Download JSON as
client_secret.json
-
Place in Project Directory:
calender-agent-service/client_secret.json -
First Run Authorization:
- Run
python app_langgraph.py - Browser opens automatically
- Sign in and grant permissions
- Token saved as
token_calender_v3.pickle
- Run
Dynamic timing configuration
class UserPreferences:
def get_current_time(self) -> datetime
def get_time_reference_hour(self, reference: str) -> intNLP-based task parsing
class TaskParser:
@staticmethod
def parse(text: str) -> ParsedTask
def extract_deadline(text: str) -> Optional[str]
def detect_priority(text: str) -> TaskPriority
def classify_category(text: str) -> strTask management
class TaskAgent:
def process_task(message: str) -> Dict[str, Any]
def generate_summary(existing_tasks: List[Dict]) -> strAll nodes in nodes.py:
preprocess_user_message_node: Input cleanuprouter_node: Intent classificationparse_calendar_request_node: Extract operationsreasoning_and_conflict_detection_node: Analyze constraintscheck_approval_node: Determine approval needexecute_calendar_workflow_node: Perform actionsformat_response_node: Create responses
Functions in calendar_tools.py:
list_calendar_list(): List all calendarscreate_calendar_list(): Create calendarlist_calendar_events(): List eventsinsert_calendar_event(): Create eventdelete_calendar_event(): Delete eventsearch_events(): Search events
Every file explained:
| File | Purpose |
|---|---|
app_langgraph.py |
Main FastAPI server + Task Agent |
graph.py |
LangGraph workflow definition |
nodes.py |
Workflow node implementations (1917 lines) |
state.py |
CalendarState TypedDict |
calendar_tools.py |
Google Calendar API wrapper |
constraint_agent.py |
Constraint identification |
clarification_agent.py |
Clarification logic |
google_apis.py |
OAuth and API client setup |
langfuse_integration.py |
Observability hooks |
requirements.txt |
Python dependencies |
.env |
Configuration (create this) |
client_secret.json |
Google OAuth (download from GCP) |
token_calender_v3.pickle |
Auth token (auto-generated) |
In app_langgraph.py:
CATEGORIES = {
"work": ["meeting", "deadline", ...],
"your_category": ["keyword1", "keyword2"]
}In UserPreferences.get_time_reference_hour():
references = {
"your_reference": 10, # 10 AM
# ...
}- Add function to
calendar_tools.py - Handle in
execute_calendar_workflow_nodeinnodes.py - Update
actionliteral instate.py
Solution:
# Check .env exists
cat .env
# Verify format
GROQ_API_KEY=gsk_...
# Restart serviceSolution:
# Delete token
rm token_calender_v3.pickle
# Restart and re-authorize
python app_langgraph.pySolution:
# Windows
netstat -ano | findstr :8000
taskkill /PID <pid> /F
# Linux/Mac
lsof -ti:8000 | xargs kill -9
# Or change PORT in .envSolution:
- Check
USER_TIMEZONEin.env - Use format:
America/New_York - Test with explicit dates
- Check console logs
Solution:
Edit clarification_agent.py:
# Increase threshold
CONFIDENCE_THRESHOLD = 0.8 # default 0.7Solution:
- Use exact event title or close match
- Check which calendar the event is in
- Use context: Create event first, then say "move it to..."
- Try: "Reschedule [exact event name] to [new time]"
Example:
# β Won't work if event doesn't exist
"Reschedule my meeting to 3pm"
# β
Better - create context first
User: "Schedule team standup tomorrow at 2pm"
Agent: "β
Created: team standup"
User: "Move it to 3pm"
Agent: "β
Rescheduled to 3pm"Solution: The rule-based parser now checks for reschedule keywords. If you're creating a new event with a time range, it should work:
# β
Creates new event
"I have a meeting from 3pm to 4pm"
# β
Reschedules existing event
"Reschedule my meeting from 1pm to 2pm"Solution: Use clear sequential indicators:
# β
Good
"Schedule research tomorrow, then slides the next day, then practice the day after"
# β Avoid vague
"Schedule research, slides, and practice" (no dates specified)Enable verbose logging:
# In app_langgraph.py
import logging
logging.basicConfig(level=logging.DEBUG)Reduce LLM Calls:
- Cache repeated queries
- Increase confidence threshold
- Batch operations
Speed Up Calendar:
- Use specific calendar_id
- Reduce max_capacity
- Cache calendar list
- FastAPI: https://fastapi.tiangolo.com/
- LangGraph: https://python.langchain.com/docs/langgraph
- Groq: https://console.groq.com/docs
- Google Calendar API: https://developers.google.com/calendar/api
- Langfuse: https://langfuse.com/docs
- Groq: https://console.groq.com/ (free tier available)
- Langfuse: https://cloud.langfuse.com/ (optional, for observability)
Contributions welcome! Please:
- Fork the repository
- Create feature branch
- Make changes with tests
- Submit pull request
For issues or questions:
- Email: rupeshvarshney7@gmail.com, bhomikvarshney@gmail.com
- GitHub: https://github.com/rupeshv2121/Amulate-BMW-Group
Built with β€οΈ using LangGraph, FastAPI, and Groq
One unified service for intelligent calendar and task management!