From 9874d20da553af75399e0684111c770005c0dc2c Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Wed, 10 Jun 2026 14:38:19 -0400 Subject: [PATCH] Remove dead exec-aide-reminder Lambda (INFRA-37) (#54) * Remove dead exec-aide-reminder Lambda and its IAM role The reminder Lambda had 0 invocations in 90 days and no EventBridge rule targets it. Removing the Lambda, its execution role, the dedicated ReminderSchedulerRole, and the scheduler:CreateSchedule / iam:PassRole grants from the conversation Lambda's policy. The conversation Lambda's REMINDER_FN_ARN and REMINDER_SCHEDULER_ROLE_ARN env vars and the create_reminder tool are removed alongside the infrastructure. The src/reminder/ handler directory is also deleted. Adam approved the deletion (INFRA-37). Refs: INFRA-37 * fix: remove unused os import in conversation/tools.py Left dangling after the exec-aide-reminder removal (INFRA-37); ruff F401. INFRA-37 --- lib/constructs/email-pipeline.ts | 41 +-------------------------- src/conversation/app.py | 5 +--- src/conversation/tools.py | 48 +------------------------------- src/reminder/__init__.py | 0 src/reminder/app.py | 26 ----------------- 5 files changed, 3 insertions(+), 117 deletions(-) delete mode 100644 src/reminder/__init__.py delete mode 100644 src/reminder/app.py diff --git a/lib/constructs/email-pipeline.ts b/lib/constructs/email-pipeline.ts index 2dca042..5e1343c 100644 --- a/lib/constructs/email-pipeline.ts +++ b/lib/constructs/email-pipeline.ts @@ -169,31 +169,6 @@ export class EmailPipelineConstruct extends Construct { sourceArn: `arn:aws:scheduler:${region}:${account}:schedule/default/${schedule.name}`, }); - // ── Reminder Lambda ────────────────────────────────────── - - const reminder = new PythonFunction(this, 'Reminder', { - functionName: 'exec-aide-reminder', - entry: path.join(__dirname, '../../src'), - index: 'reminder/app.py', - handler: 'lambda_handler', - runtime: lambda.Runtime.PYTHON_3_12, - architecture: lambda.Architecture.ARM_64, - memorySize: 128, - timeout: cdk.Duration.seconds(30), - environment: lambdaEnv, - logRetention: logs.RetentionDays.TWO_MONTHS, - }); - - this.table.grantReadData(reminder); - reminder.addToRolePolicy(secretsReadPolicy); - reminder.addToRolePolicy(ssmPolicy); - - const reminderSchedulerRole = new iam.Role(this, 'ReminderSchedulerRole', { - roleName: 'exec-aide-reminder-scheduler', - assumedBy: new iam.ServicePrincipal('scheduler.amazonaws.com'), - }); - reminder.grantInvoke(reminderSchedulerRole); - // ── Conversation Lambda ─────────────────────────────────── const conversation = new PythonFunction(this, 'Conversation', { @@ -205,11 +180,7 @@ export class EmailPipelineConstruct extends Construct { architecture: lambda.Architecture.ARM_64, memorySize: 512, timeout: cdk.Duration.seconds(180), - environment: { - ...lambdaEnv, - REMINDER_FN_ARN: reminder.functionArn, - REMINDER_SCHEDULER_ROLE_ARN: reminderSchedulerRole.roleArn, - }, + environment: lambdaEnv, logRetention: logs.RetentionDays.TWO_MONTHS, }); @@ -224,16 +195,6 @@ export class EmailPipelineConstruct extends Construct { `arn:aws:bedrock:${region}:${account}:inference-profile/us.anthropic.*`, ], })); - conversation.addToRolePolicy(new iam.PolicyStatement({ - actions: ['scheduler:CreateSchedule', 'scheduler:DeleteSchedule'], - resources: [ - `arn:aws:scheduler:${region}:${account}:schedule/default/exec-aide-reminder-*`, - ], - })); - conversation.addToRolePolicy(new iam.PolicyStatement({ - actions: ['iam:PassRole'], - resources: [reminderSchedulerRole.roleArn], - })); dailyDigest.grantInvoke(conversation); this.conversationFn = conversation; diff --git a/src/conversation/app.py b/src/conversation/app.py index 67ffad1..a6e2640 100644 --- a/src/conversation/app.py +++ b/src/conversation/app.py @@ -39,10 +39,7 @@ When referencing emails, always include the sender name and subject line. \ For time references, use relative terms (e.g., "2 hours ago", "yesterday"). You can manage Adam's task list — create tasks, list them, mark them \ -complete, or delete them. You can also set reminders that will send a Slack \ -DM at a specified time. When Adam asks to be reminded of something, use \ -create_reminder with the appropriate date/time (default timezone: \ -America/New_York). +complete, or delete them. You have access to Adam's Google Calendar. You can view upcoming events, \ check availability, and create new events. Always confirm event details \ diff --git a/src/conversation/tools.py b/src/conversation/tools.py index 0cf04a7..131e87a 100644 --- a/src/conversation/tools.py +++ b/src/conversation/tools.py @@ -1,6 +1,5 @@ import json import logging -import os from datetime import datetime, timezone import boto3 @@ -264,28 +263,6 @@ TOOLS = [ }, } }, - { - "toolSpec": { - "name": "create_reminder", - "description": "Set a reminder that will send Adam a Slack DM at a specific time.", - "inputSchema": { - "json": { - "type": "object", - "properties": { - "text": { - "type": "string", - "description": "The reminder message text.", - }, - "remind_at": { - "type": "string", - "description": "When to send the reminder in ISO 8601 format (e.g., 2026-05-05T09:00:00). Timezone is America/New_York.", - }, - }, - "required": ["text", "remind_at"], - } - }, - } - }, { "toolSpec": { "name": "get_calendar_events", @@ -411,7 +388,6 @@ def dispatch_tool(tool_name, tool_input): "list_tasks": _handle_list_tasks, "complete_task": _handle_complete_task, "delete_task": _handle_delete_task, - "create_reminder": _handle_create_reminder, "get_calendar_events": _handle_get_calendar_events, "create_calendar_event": _handle_create_calendar_event, "check_availability": _handle_check_availability, @@ -601,7 +577,7 @@ def _handle_coordinate(inputs): } -# ── Task & Reminder Handlers ────────────────────────────────── +# ── Task Handlers ────────────────────────────────── def _handle_create_task(inputs): @@ -637,28 +613,6 @@ def _handle_delete_task(inputs): return {"task_id": inputs["task_id"], "status": "deleted"} -def _handle_create_reminder(inputs): - import ulid as _ulid - - scheduler = boto3.client("scheduler") - schedule_name = f"exec-aide-reminder-{_ulid.new()}" - remind_at = inputs["remind_at"] - - scheduler.create_schedule( - Name=schedule_name, - ScheduleExpression=f"at({remind_at})", - ScheduleExpressionTimezone="America/New_York", - FlexibleTimeWindow={"Mode": "OFF"}, - Target={ - "Arn": os.environ["REMINDER_FN_ARN"], - "RoleArn": os.environ["REMINDER_SCHEDULER_ROLE_ARN"], - "Input": json.dumps({"text": inputs["text"]}), - }, - ActionAfterCompletion="DELETE", - ) - return {"status": "scheduled", "remind_at": remind_at, "text": inputs["text"]} - - # ── Calendar Handlers ────────────────────────────────────────── diff --git a/src/reminder/__init__.py b/src/reminder/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/reminder/app.py b/src/reminder/app.py deleted file mode 100644 index 00d0c62..0000000 --- a/src/reminder/app.py +++ /dev/null @@ -1,26 +0,0 @@ -import logging - -from shared.secrets import get_config, get_slack_token -from shared.slack import post_message - -logger = logging.getLogger() -logger.setLevel(logging.INFO) - - -def lambda_handler(event, context): - text = event.get("text", "Reminder (no details provided)") - config = get_config() - token = get_slack_token() - - import requests - - resp = requests.post( - "https://slack.com/api/conversations.open", - headers={"Authorization": f"Bearer {token}"}, - json={"users": config["adam_slack_user_id"]}, - ) - resp.raise_for_status() - channel = resp.json()["channel"]["id"] - - post_message(channel, f":bell: *Reminder:* {text}", token) - logger.info("Reminder sent: %s", text)