Skip to content

Commit bf312cd

Browse files
authored
[agent,nextjs,react] move Agent from constantinius, integrate deploy, delete old NextJS agent (#1165)
* [agent,nextjs,react] move Agent from constantinius, integrate deploy, delete old NextJS agent * fixes * use AGENT_URL_STAGING in staging and local
1 parent d55fb30 commit bf312cd

36 files changed

+1372
-224
lines changed

.local.env.base

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ SENTRY_ORG= # ** Fill in **
22
# -- line to prevent conflicts --
33
SENTRY_AUTH_TOKEN=${__ENV__} # set in ~/.zshrc, must have permissions to your org
44
GCP_PROJECT=sales-engineering-sf
5+
GCP_REGION=us-central1
56
DB_CLOUD_SQL_CONNECTION_NAME=${__GCP_SECRET__}
67
DB_DATABASE=hardwarestore
78
DB_HOST=${__GCP_SECRET__}
@@ -14,7 +15,8 @@ SPRINGBOOT_URL=${__IF_DEPLOYING__(spring-boot, http://localhost:$SPRINGBOOT_LOCA
1415
ASPNETCORE_URL=${__IF_DEPLOYING__(aspnetcore, http://localhost:$ASPNETCORE_LOCAL_PORT, ${__GCP_SECRET__(ASPNETCORE_URL_STAGING)})}
1516
LARAVEL_URL=${__IF_DEPLOYING__(laravel, http://localhost:$LARAVEL_LOCAL_PORT, ${__GCP_SECRET__(LARAVEL_URL_STAGING)})}
1617
RUBYONRAILS_URL=${__IF_DEPLOYING__(ruby-on-rails, http://localhost:$RUBYONRAILS_LOCAL_PORT, ${__GCP_SECRET__(RUBYONRAILS_URL_STAGING)})}
17-
OPENAI_API_KEY=${__GCP_SECRET__}
18+
AGENT_URL=${__IF_DEPLOYING__(agent, http://localhost:$AGENT_LOCAL_PORT, ${__GCP_SECRET__(AGENT_URL_STAGING)})}
19+
MCP_URL=${__GCP_SECRET__} # Using production for now
1820

1921
# Note prefix change in _.env.template
2022
REACT_DSN= # ** Fill in **
@@ -119,3 +121,9 @@ SPRINGBOOTOTLP_SENTRY_PROJECT=spring-boot-otlp
119121
# -- line to prevent conflicts --
120122
SPRINGBOOTOTLP_CLOUD_GCP_SQL_ENABLED=false
121123
SPRINGBOOTOTLP_RELEASE=empower.springboototlp@${__DYNAMIC_VERSION__}
124+
125+
AGENT_DSN=${__GCP_SECRET__(AGENT_DSN_STAGING)}
126+
AGENT_LOCAL_PORT=8093
127+
# -- line to prevent conflicts --
128+
AGENT_OPENAI_API_KEY=${__GCP_SECRET__} # owned by EPD
129+
AGENT_SENTRY_ENVIRONMENT=local

README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,6 @@ gcloud app logs tail -s <SERVICE>
186186

187187
`gcloud app deploy` does not support `--update-env-vars RELEASE=$RELEASE` like `gcloud run deploy` does with Cloud Run
188188

189-
## AI Suggestions (nextjs -> flask)
190-
191-
1. Run next and flask (./deploy --env=local next flask)
192-
2. Get suggestion button should show automatically
193189

194190
## Caches & Queues (flask)
195191

@@ -226,4 +222,3 @@ When the script is terminated (e.g., with Ctrl+C), it performs cleanup to ensure
226222
- Once you have Vercel access run `vercel dev` command from the `empower` repo
227223
- Following the prompts, select the Sentry org from and the empower project. A vercel config file will be created the first time you do this.
228224
- App should run on `localhost:3000`
229-

_bin/ensure_docker.sh

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/bin/bash
2+
3+
# Ensure Docker (via Colima) is available for local development
4+
# Usage: source this script or call it directly
5+
# source ensure_docker.sh # exports DOCKER_HOST to current shell
6+
# ./ensure_docker.sh # just verifies docker is working
7+
8+
set -e
9+
10+
# Set Docker host to Colima's socket (must be set before any docker commands)
11+
export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock"
12+
13+
ensure_docker() {
14+
# Check for Homebrew
15+
if ! command -v brew &> /dev/null; then
16+
echo "Error: Homebrew is required to install dependencies. Install from https://brew.sh"
17+
exit 1
18+
fi
19+
20+
# Install Docker CLI if not present
21+
if ! command -v docker &> /dev/null; then
22+
echo "Installing Docker CLI..."
23+
brew install docker
24+
fi
25+
26+
# Install docker-compose if not present
27+
if ! command -v docker-compose &> /dev/null; then
28+
echo "Installing docker-compose..."
29+
brew install docker-compose
30+
fi
31+
32+
# Install Colima if not present
33+
if ! command -v colima &> /dev/null; then
34+
echo "Installing Colima..."
35+
brew install colima
36+
fi
37+
38+
# Start Colima if not running or socket doesn't exist
39+
if ! colima status &> /dev/null || [ ! -S "${HOME}/.colima/default/docker.sock" ]; then
40+
echo "Starting Colima..."
41+
colima start
42+
fi
43+
44+
# Verify Docker is working
45+
echo "Verifying Docker connection (DOCKER_HOST=$DOCKER_HOST)..."
46+
if ! docker info &> /dev/null; then
47+
echo "Error: Docker not responding. Trying to restart Colima..."
48+
colima stop 2>/dev/null || true
49+
colima start
50+
if ! docker info &> /dev/null; then
51+
echo "Error: Docker still not responding after restarting Colima"
52+
exit 1
53+
fi
54+
fi
55+
echo "Docker is ready."
56+
}
57+
58+
ensure_docker

agent/Dockerfile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Use Python 3.11 slim image
2+
FROM python:3.11-slim
3+
4+
# Set working directory
5+
WORKDIR /app
6+
7+
# Install system dependencies
8+
RUN apt-get update && apt-get install -y \
9+
gcc \
10+
&& rm -rf /var/lib/apt/lists/*
11+
12+
# Copy requirements first for better caching
13+
COPY requirements.txt .
14+
15+
# Install Python dependencies
16+
RUN pip install --no-cache-dir -r requirements.txt
17+
18+
# Copy application code
19+
COPY . .
20+
21+
# Create non-root user
22+
RUN useradd --create-home --shell /bin/bash app \
23+
&& chown -R app:app /app
24+
USER app
25+
26+
# Expose port (Cloud Run uses PORT env var, defaults to 8080)
27+
EXPOSE $PORT
28+
29+
# Run the application
30+
CMD ["python", "main.py"]

agent/Makefile

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
.PHONY: install format lint test clean dev-setup
2+
3+
# Install dependencies
4+
install:
5+
pip install -r requirements.txt
6+
7+
# Development setup
8+
dev-setup: install
9+
pre-commit install
10+
@echo "Development environment setup complete!"
11+
@echo "Auto import sorting and formatting will now run on git commits."
12+
13+
# Format code
14+
format:
15+
isort . --profile black --line-length 88
16+
black . --line-length 88
17+
18+
# Lint code
19+
lint:
20+
flake8 . --max-line-length 88 --extend-ignore E203,W503
21+
mypy . --ignore-missing-imports
22+
isort . --profile black --line-length 88 --check-only
23+
24+
# Run tests
25+
test:
26+
pytest
27+
28+
# Clean up generated files
29+
clean:
30+
find . -type d -name "__pycache__" -delete
31+
find . -type f -name "*.pyc" -delete
32+
find . -type d -name "*.egg-info" -exec rm -rf {} +
33+
find . -type d -name ".pytest_cache" -delete
34+
find . -type d -name ".mypy_cache" -delete
35+
36+
# Run the application
37+
run:
38+
python main.py
39+
40+
# Run with Docker
41+
docker-run:
42+
docker-compose up --build
43+
44+
# Sort imports manually
45+
sort-imports:
46+
isort . --profile black --line-length 88

agent/README.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# Simple Plant Care AI Agent
2+
3+
A simple FastAPI-based plant care AI assistant powered by the OpenAI Agents SDK. Just provide a plant name and get personalized care advice!
4+
5+
## Features
6+
7+
- 🌱 **Simple Plant Care Agent**: Get care advice for any plant by name
8+
- 🛠️ **One Tool**: Basic plant care database with common houseplants
9+
- 🚀 **FastAPI Backend**: Modern, fast API with automatic docs
10+
- 📚 **Interactive API Docs**: Built-in Swagger UI at `/docs`
11+
- 🎯 **Minimal Dependencies**: Bare bones implementation following OpenAI Agents SDK
12+
13+
## Quick Start
14+
15+
### Prerequisites
16+
17+
- Python 3.11+
18+
- OpenAI API key
19+
20+
### Installation
21+
22+
1. **Clone the repository**
23+
24+
```bash
25+
git clone <repository-url>
26+
cd empower-plant-agent-demo
27+
```
28+
29+
2. **Set up environment variables**
30+
31+
```bash
32+
export OPENAI_API_KEY=sk-your-api-key-here
33+
```
34+
35+
3. **Install dependencies**
36+
37+
```bash
38+
pip install -r requirements.txt
39+
```
40+
41+
4. **Run the application**
42+
```bash
43+
python main.py
44+
```
45+
46+
The API will be available at `http://localhost:8000` with interactive docs at `http://localhost:8000/docs`.
47+
48+
## Usage
49+
50+
### API Endpoint
51+
52+
**POST** `/api/v1/plant-care`
53+
54+
Request body:
55+
56+
```json
57+
{
58+
"plant_name": "pothos"
59+
}
60+
```
61+
62+
Response:
63+
64+
```json
65+
{
66+
"response": "🌱 **Pothos Care Guide**\n\n**Watering**: Water when top inch of soil is dry (every 1-2 weeks)\n**Light**: Bright, indirect light\n**Pro Tip**: Very forgiving plant, great for beginners. Can tolerate low light.\n\n**General Care Reminders**:\n• Check soil moisture before watering\n• Ensure good drainage\n• Watch for signs of overwatering (yellow leaves)\n• Rotate plant occasionally for even growth",
67+
"agent_name": "PlantCareAgent"
68+
}
69+
```
70+
71+
### Direct Python Usage
72+
73+
```python
74+
import asyncio
75+
from app.agents.simple_plant_agent import process_plant_query
76+
77+
async def main():
78+
advice = await process_plant_query("snake plant")
79+
print(advice)
80+
81+
asyncio.run(main())
82+
```
83+
84+
### Example with curl
85+
86+
```bash
87+
curl -X POST "http://localhost:8000/api/v1/plant-care" \
88+
-H "Content-Type: application/json" \
89+
-d '{"plant_name": "monstera"}'
90+
```
91+
92+
## Supported Plants
93+
94+
The agent has specific care information for:
95+
96+
- Pothos
97+
- Snake Plant
98+
- Monstera
99+
- Fiddle Leaf Fig
100+
- Peace Lily
101+
- Rubber Plant
102+
- Succulents
103+
104+
For other plants, it provides general care advice and suggests trying the supported plants.
105+
106+
## Project Structure
107+
108+
```
109+
app/
110+
├── agents/
111+
│ └── simple_plant_agent.py # Main agent with OpenAI Agents SDK
112+
├── tools/
113+
│ └── simple_plant_tool.py # Plant care tool/function
114+
└── api/
115+
├── models.py # Pydantic request/response models
116+
└── routes.py # FastAPI routes
117+
118+
main.py # FastAPI application entry point
119+
simple_example.py # Direct usage example
120+
config.py # Configuration management
121+
```
122+
123+
## Configuration
124+
125+
Set these environment variables:
126+
127+
- `OPENAI_API_KEY`: Your OpenAI API key (required)
128+
- `light_model`: Model for the agent (default: "gpt-4o-mini")
129+
- `API_HOST`: API host (default: "0.0.0.0")
130+
- `PORT`: API port (default: 8000)
131+
132+
## Development
133+
134+
Run the simple example:
135+
136+
```bash
137+
python simple_example.py
138+
```
139+
140+
Check the API docs:
141+
142+
```bash
143+
python main.py
144+
# Visit http://localhost:8000/docs
145+
```
146+
147+
## OpenAI Agents SDK
148+
149+
This project follows the [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/) patterns:
150+
151+
- **Agent**: Simple plant care assistant with instructions
152+
- **Tool**: Function tool for plant care advice
153+
- **Runner**: Handles the agent execution loop
154+
155+
The implementation is minimal and focused, demonstrating the core concepts without complexity.

agent/app/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""App package containing API and agents modules."""

0 commit comments

Comments
 (0)