Skip to content

Commit 79e2617

Browse files
authored
Merge pull request #1 from redis-applied-ai/terraform
terraform cleanup
2 parents c7b84a2 + 10d3f10 commit 79e2617

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+3773
-1915
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,5 +192,4 @@ ai
192192
TASK_MEMORY.md
193193
.env*
194194

195-
terraform/
196195
infra/

CLAUDE.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ Important: DO NOT USE Redis Stack or other earlier versions of Redis.
1717
- `tasks.py`: Task definitions with retry logic
1818
- `rag.py`: RedisVL vector search + OpenAI generation
1919
- `web_search.py`: Tavily API integration
20-
- `glean_search.py`: Enterprise knowledge search
2120
- `db.py`: Vector index management
2221

2322
### Pipeline System (`pipelines/`)

Dockerfile.collector

Lines changed: 0 additions & 7 deletions
This file was deleted.

README.md

Lines changed: 143 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
![Language](https://img.shields.io/github/languages/top/redis-applied-ai/redis-slack-worker-agent)
66
![GitHub last commit](https://img.shields.io/github/last-commit/redis-applied-ai/redis-slack-worker-agent)
77

8-
The code in this repo shows a reference architecture for a Slack-integrated agent application running on ECS. The architecture is designed so that agent workers can scale horizontally to demand while keeping a minimal API instance running. Additionally, it implements the [agent memory server](https://github.com/redis/agent-memory-server) as a tool call for storing and automatically summarizing and persisting short and long term memory to Redis.
8+
The code in this repo shows a reference architecture for a Slack-integrated agent application running on ECS. The architecture is designed so that agent workers, API containers, and agent-memory-server can scale in a decoupled way. [The agent memory server](https://github.com/redis/agent-memory-server) itself is implemented as a tool call for storing and automatically summarizing and persisting short and long term memories.
99

1010
## Business objective
1111

@@ -16,22 +16,22 @@ Internally at Redis, this bot extends the Applied AI engineering team by assisti
1616

1717
![Application Architecture](resources/haink_task_flow.png)
1818

19-
**TLDR Flow**: Slack → FastAPI webhook → Redis task queue → Agent workers pick up and execute tasks → Agent workers perform tool calls and schedule tasks until determining to respond and invoke Slack callback.
19+
**TLDR Flow**: Slack → FastAPI webhook → Redis task queue → Agent workers pick up and execute tasks → Agent workers perform tool calls and ReAct style execution -> invoke Slack callbacks async.
2020

2121
## Core Components
2222

23-
- **FastAPI App**: Webhook handler with health checks
24-
- **Agent Engine**: ReAct methodology that runs search tools (curated AI team knowledge, internal Glean search, and web search via Tavily) in an agentic loop
25-
- **Agent memory**: Remembers past interactions with users via the [Agent Memory Server](https://github.com/redis/agent-memory-server) and personalizes responses
26-
- **Docket Workers**: Background task processing with retry logic
27-
- **Redis**: Vector database (RedisVL) + streams-based task queue + caching
23+
- **FastAPI App**: Webhook handler.
24+
- **Agent Engine**: ReAct methodology runs search tools in an agentic loop.
25+
- **Agent memory**: Remembers past interactions with users via the [Agent Memory Server](https://github.com/redis/agent-memory-server).
26+
- **Docket Workers**: Core task processing utility.
27+
- **Redis**: Vector database + streams-based task queue + memory store.
2828

2929
## Quick Start
3030

3131
### Prerequisites
3232
- Python 3.12+, Redis, UV package manager
3333
- Slack app credentials, OpenAI API key
34-
- Optional: Tavily API key for web search
34+
- Tavily API key for web search
3535

3636
### Development Setup
3737
```bash
@@ -54,27 +54,27 @@ uv run python -m app.worker
5454
# Start API (Terminal 2)
5555
uv run fastapi dev app/api/main.py
5656

57-
# Local otel collector (Optional Terminal 3)
58-
docker compose -f docker-compose.collector.yml up
5957
```
6058

61-
### Local development with Slack
59+
### Development with Slack
6260

63-
To test local changes in Slack, you can run an ngrok server locally and then connect Slack to the ngrok endpoint that proxies to your local machine.
61+
To test changes in Slack, you can run an ngrok server locally or setup with ALB with terraform (see below) and then connect Slack to the respective endpoint.
6462

65-
First, run ngrok:
63+
For ngrok, run:
6664

6765
```bash
6866
ngrok http 8000
6967
```
7068

7169
Then, in the Slack API console, update "Event Subscriptions -> Request URL" with the proxy URL ngrok gives you. It will look like `https://<ngrok proxy>/slack/events` (e.g.: `https://3cfaf9a1bcff.ngrok-free.app/slack/events`).
7270

71+
![Application Architecture](resources/slack_subscription.png)
72+
7373
Additionally, if persisting answer feedback locally, update "Interactivity & Shortcuts -> Request URL" with the URL `https://<ngrok proxy>/slack/interactive`.
7474

7575
## Usage
7676

77-
**Slack**: Mention `@bot` in any channel. The bot processes questions using ReAct methodology with search tools (curated AI knowledge, internal docs with Glean, and web search).
77+
**Slack**: Mention `@bot` in any channel. The bot processes questions using ReAct methodology with search tools (curated AI knowledge and web search).
7878

7979
**API**:
8080
- Health: `GET /health`
@@ -89,12 +89,139 @@ Essential environment variables:
8989
SLACK_BOT_TOKEN=xoxb-your-bot-token
9090
SLACK_SIGNING_SECRET=your-signing-secret
9191
OPENAI_API_KEY=your-openai-key
92-
93-
# Optional
9492
TAVILY_API_KEY=your-tavily-key # Web search tool
9593
REDIS_URL=redis://localhost:6379/0
9694
```
9795

96+
## Deployment (AWS, single environment)
97+
98+
This reference deploys a working agent stack on AWS with a single `terraform apply`:
99+
VPC, ALB, ECS Fargate (API, Worker, Memory Server), ECR, S3, IAM, and basic CloudWatch.
100+
No domain or SSL is required; the ALB exposes HTTP for testing.
101+
102+
Development environment requirements
103+
- Terraform v1.10 or later
104+
- AWS CLI configured with credentials
105+
- Docker (to build and push images)
106+
- Agent Memory Server [credentials](https://redis.github.io/agent-memory-server/authentication/?h=secret#token-management-commands)
107+
108+
Prerequisites
109+
- AWS account with permissions for VPC, ECS (Fargate), ECR, ALB, IAM, S3, CloudWatch
110+
- Slack app credentials (bot token, signing secret)
111+
- OpenAI API key
112+
- Cloud-accessible Redis URL (e.g., Upstash or ElastiCache). Localhost will not work from ECS.
113+
- Tavily API key (web search)
114+
115+
Terraform modules
116+
- VPC: networking, subnets, security groups
117+
- ECR: container repositories
118+
- ECS: Fargate cluster, API and worker services, Memory Server sidecar (separate service)
119+
- ALB: public Load Balancer routing to API and Memory Server health
120+
- S3: content bucket for uploads/examples
121+
- IAM: roles and policies for ECS/ECR/S3/SSM
122+
- Monitoring: CloudWatch dashboard and alarms (basic)
123+
124+
Step 1) Configure minimal variables
125+
Create or edit `terraform/terraform.tfvars` (example):
126+
```hcl
127+
aws_region = "us-east-1"
128+
project_name = "my-ai-agent" # choose your own unique name
129+
bucket_name = "my-ai-agent-content-1234" # must be globally unique
130+
```
131+
132+
Step 2) Seed required secrets into AWS SSM
133+
- Copy the example and fill in values: `cp .env.example .env && edit .env`
134+
- Then run the loader script to write SSM parameters under `/${project_name}/...`
135+
- IMPORTANT: Use a cloud Redis URL for `REDIS_URL` (not localhost)
136+
```bash
137+
set -a; source .env; \
138+
export PROJECT_NAME="my-ai-agent" AWS_REGION="us-east-1"; \
139+
# Required for cloud: set a token and the base URL the app will call
140+
export AGENT_MEMORY_SERVER_API_KEY="generate-a-strong-token"; \
141+
# Get ALB DNS dynamically (ALB routes /v1/* to memory server):
142+
export AGENT_MEMORY_SERVER_URL="http://$(terraform -chdir=terraform output -raw alb_dns_name)"; \
143+
set +a; sh ./scripts/load_secrets.sh
144+
```
145+
See the full list of parameters in `terraform/SSM_PARAMETERS.md`.
146+
147+
Step 3) Deploy the infrastructure
148+
Use the helper script or terraform directly:
149+
```bash
150+
# Using helper script
151+
./terraform/deploy.sh apply
152+
153+
# Or manually
154+
terraform -chdir=terraform init
155+
terraform -chdir=terraform validate
156+
terraform -chdir=terraform plan -out=tfplan
157+
terraform -chdir=terraform apply tfplan
158+
```
159+
After apply, note the `application_url` output (ALB HTTP URL).
160+
161+
Step 4) Build and push images to ECR
162+
163+
**CRITICAL**: ECS Fargate runs on X86_64 (amd64) architecture. Always build with `--platform linux/amd64` to avoid "exec format error" failures.
164+
165+
```bash
166+
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
167+
AWS_REGION=us-east-1
168+
ECR="$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"
169+
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin "$ECR"
170+
171+
# API (build for linux/amd64)
172+
docker build --platform linux/amd64 -f Dockerfile.api -t "$ECR/my-ai-agent-api:latest" .
173+
docker push "$ECR/my-ai-agent-api:latest"
174+
175+
# Worker (build for linux/amd64)
176+
docker build --platform linux/amd64 -f Dockerfile.worker -t "$ECR/my-ai-agent-worker:latest" .
177+
docker push "$ECR/my-ai-agent-worker:latest"
178+
```
179+
180+
**Note**: If you encounter "No space left on device" during `uv sync`, increase Docker Desktop disk allocation (Settings → Resources → Disk image size).
181+
182+
**Optional - Test locally before pushing**:
183+
```bash
184+
# Verify architecture
185+
docker image inspect "$ECR/my-ai-agent-api:latest" --format '{{.Architecture}}' # should show "amd64"
186+
187+
# Quick smoke test (requires .env file)
188+
docker run --rm --env-file .env -p 3000:3000 "$ECR/my-ai-agent-api:latest" &
189+
sleep 5 && curl -sf http://localhost:3000/health && echo "✓ API health OK"
190+
docker stop $(docker ps -q --filter ancestor="$ECR/my-ai-agent-api:latest")
191+
192+
# Verify git binary is present (prevents GitPython errors)
193+
docker run --rm "$ECR/my-ai-agent-worker:latest" git --version
194+
docker run --rm "$ECR/my-ai-agent-worker:latest" python -c "import git; print('GitPython OK')"
195+
```
196+
197+
Step 5) Force ECS services to deploy latest images
198+
```bash
199+
aws ecs update-service --cluster my-ai-agent-cluster \
200+
--service my-ai-agent-api-service --force-new-deployment
201+
aws ecs update-service --cluster my-ai-agent-cluster \
202+
--service my-ai-agent-worker-service --force-new-deployment
203+
```
204+
205+
Step 6) Verify health
206+
```bash
207+
APP_URL=$(terraform -chdir=terraform output -raw application_url)
208+
curl -i "$APP_URL/health"
209+
curl -i "$APP_URL/v1/health"
210+
```
211+
212+
Step 7) Configure Slack and test
213+
- Event Subscriptions → Enable → Request URL: `<application_url>/slack/events`
214+
- Interactivity & Shortcuts → Enable → Request URL: `<application_url>/slack/interactive`
215+
- Subscribe to bot events (at minimum): `app_mention`, `message.channels`, `message.im`
216+
Test by mentioning the bot in a channel or DM.
217+
218+
> See Development with Slack section for visual on how to update this value.
219+
220+
Cleanup
221+
```bash
222+
terraform -chdir=terraform destroy
223+
```
224+
98225
## Testing
99226

100227
```bash

app/agent/__init__.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,8 @@
1919

2020
# Re-export all tools
2121
from .tools import (
22-
GleanSearchService,
23-
get_glean_service,
2422
get_search_tool_config,
2523
perform_web_search,
26-
search_glean,
2724
search_knowledge_base,
2825
search_knowledge_base_with_metadata,
2926
)
@@ -38,11 +35,8 @@
3835
"is_brief_satisfied_response",
3936
"SYSTEM_PROMPT",
4037
# Tool functions
41-
"GleanSearchService",
42-
"get_glean_service",
4338
"get_search_tool_config",
4439
"perform_web_search",
45-
"search_glean",
4640
"search_knowledge_base",
4741
"search_knowledge_base_with_metadata",
4842
# All task functions are available via the wildcard import

app/agent/agent.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from .tasks import *
2020

2121
# Re-export all tools
22-
from .tools import get_glean_search_tool, get_search_tool, get_web_search_tool
22+
from .tools import get_search_knowledge_base_tool, get_web_search_tool
2323

2424
# For backward compatibility, also export the main functions directly
2525
__all__ = [
@@ -31,8 +31,7 @@
3131
"is_brief_satisfied_response",
3232
"retrieve_context",
3333
# Tool functions
34-
"get_search_tool",
34+
"get_search_knowledge_base_tool",
3535
"get_web_search_tool",
36-
"get_glean_search_tool",
3736
# All task functions are available via the wildcard import
3837
]

app/agent/core.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,7 @@
1919
from redisvl.index.index import AsyncSearchIndex
2020
from redisvl.utils.vectorize import OpenAITextVectorizer
2121

22-
from app.agent.tools import (
23-
get_glean_search_tool,
24-
get_search_knowledge_base_tool,
25-
get_web_search_tool,
26-
)
22+
from app.agent.tools import get_search_knowledge_base_tool, get_web_search_tool
2723
from app.utilities.openai_client import get_instrumented_client
2824

2925
logger = logging.getLogger(__name__)
@@ -334,7 +330,6 @@ async def answer_question(
334330
tools = [
335331
get_search_knowledge_base_tool(),
336332
get_web_search_tool(),
337-
get_glean_search_tool(),
338333
*MemoryAPIClient.get_all_memory_tool_schemas(),
339334
]
340335

app/agent/tools/__init__.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@
44
This package contains all tool modules for the agent.
55
"""
66

7-
from .glean_search import (
8-
GleanSearchService,
9-
get_glean_search_tool,
10-
get_glean_service,
11-
search_glean,
12-
)
137
from .search_knowledge_base import (
148
get_search_knowledge_base_tool,
159
get_search_tool_config,
@@ -19,10 +13,6 @@
1913
from .web_search import get_web_search_tool, perform_web_search
2014

2115
__all__ = [
22-
"GleanSearchService",
23-
"get_glean_search_tool",
24-
"get_glean_service",
25-
"search_glean",
2616
"get_search_knowledge_base_tool",
2717
"get_search_tool_config",
2818
"search_knowledge_base",

0 commit comments

Comments
 (0)