687 lines
15 KiB
Markdown
687 lines
15 KiB
Markdown
# 🚀 AI Dev Factory - Session Continuation Guide
|
|
|
|
**Last Updated:** 2024-11-28
|
|
**Current Phase:** Phase 2 - OpenHands Integration (API Mode)
|
|
**Time to Completion:** ~3-4 hours
|
|
**Next Approach:** OpenHands Server API Mode ✅
|
|
|
|
---
|
|
|
|
## 📊 CURRENT STATUS
|
|
|
|
### ✅ What's Working:
|
|
- **Gitea:** https://git.oky.sh (HTTPS, PostgreSQL backend)
|
|
- **n8n:** https://n8n.oky.sh (HTTPS, workflow automation)
|
|
- **Caddy:** Auto SSL with Let's Encrypt
|
|
- **SSH:** n8n → localhost credentials configured
|
|
- **OpenHands CLI:** `/home/bam/.local/bin/openhands` (v1.3.0)
|
|
|
|
### ⚠️ Current Blocker:
|
|
- OpenHands headless mode (Docker) hangs on runtime startup
|
|
- **Solution:** Switch to OpenHands Server API mode
|
|
|
|
### 🎯 Goal:
|
|
Create automated workflow: Gitea push → n8n → OpenHands API → Build/Test
|
|
|
|
---
|
|
|
|
## 🔧 SYSTEM CONFIGURATION
|
|
|
|
### VM Details:
|
|
```
|
|
Hostname: ai-dev-node
|
|
IP: 10.10.10.11
|
|
User: bam
|
|
CPU: 8 vCPU
|
|
RAM: 24GB (optimized from 40GB)
|
|
OS: Ubuntu 22.04
|
|
```
|
|
|
|
### Services Running:
|
|
```bash
|
|
docker compose ps
|
|
# Expected output:
|
|
# - caddy (ports 80, 443)
|
|
# - gitea (port 3333 internal, 2229 SSH)
|
|
# - n8n (port 5678 internal)
|
|
# - postgres (port 5432 internal)
|
|
```
|
|
|
|
### Important Directories:
|
|
```
|
|
/home/bam/services-stack/ # Docker services (Gitea, n8n, Caddy)
|
|
/home/bam/.local/bin/ # OpenHands CLI
|
|
/home/bam/.openhands/ # OpenHands config & sessions
|
|
├── agent_settings.json # Agent configuration
|
|
├── cache/ # Model cache
|
|
├── conversations/ # Chat history
|
|
├── sessions/ # Active sessions data
|
|
└── settings.json # LLM & server settings
|
|
/home/bam/workspace/ # Default workspace for builds
|
|
/home/bam/.ssh/n8n_key # SSH key for n8n automation
|
|
```
|
|
|
|
### API Keys Location:
|
|
```
|
|
/home/bam/openhands/.env
|
|
# Contains:
|
|
# MINIMAX_API_KEY=xxx (Primary LLM)
|
|
# DEEPSEEK_API_KEY=xxx (Backup LLM)
|
|
# OPENAI_API_KEY=xxx (Optional 2nd backup)
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 NEXT STEPS: OpenHands Server API Setup
|
|
|
|
### Step 1: Start OpenHands in Server Mode (15 min)
|
|
|
|
**Goal:** Run OpenHands as persistent HTTP API service
|
|
|
|
**OpenHands serve uses port 3000 by default (cannot be changed in current version)**
|
|
|
|
```bash
|
|
# Test server startup
|
|
/home/bam/.local/bin/openhands serve
|
|
|
|
# Expected: Server starts, listens on http://localhost:3000
|
|
```
|
|
|
|
**Create systemd service for persistence:**
|
|
```bash
|
|
sudo nano /etc/systemd/system/openhands.service
|
|
|
|
# Paste:
|
|
[Unit]
|
|
Description=OpenHands Server
|
|
After=network.target docker.service
|
|
Requires=docker.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=bam
|
|
WorkingDirectory=/home/bam
|
|
Environment="PATH=/home/bam/.local/bin:/usr/local/bin:/usr/bin:/bin"
|
|
EnvironmentFile=/home/bam/openhands/.env
|
|
ExecStart=/home/bam/.local/bin/openhands serve
|
|
Restart=always
|
|
RestartSec=10
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
|
|
# Save and enable:
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable openhands.service
|
|
sudo systemctl start openhands.service
|
|
sudo systemctl status openhands.service
|
|
```
|
|
|
|
**Verify:**
|
|
```bash
|
|
# Check if running
|
|
curl http://localhost:3000/
|
|
|
|
# Check logs
|
|
sudo journalctl -u openhands.service -f
|
|
```
|
|
|
|
---
|
|
|
|
### Step 1.5: Configure Backup LLM Models (10 min)
|
|
|
|
**Goal:** Setup DeepSeek V2 as fallback when MiniMax fails
|
|
|
|
OpenHands can use multiple LLM providers with automatic fallback.
|
|
|
|
**Check current config:**
|
|
```bash
|
|
cat /home/bam/.openhands/settings.json
|
|
```
|
|
|
|
**Update settings to include backup models:**
|
|
```bash
|
|
nano /home/bam/.openhands/settings.json
|
|
```
|
|
|
|
**Add LLM configuration:**
|
|
```json
|
|
{
|
|
"LLM_MODEL": "openai/MiniMax-M2",
|
|
"LLM_API_KEY": "${MINIMAX_API_KEY}",
|
|
"LLM_BASE_URL": "https://api.minimax.io/v1",
|
|
|
|
"LLM_FALLBACK_MODELS": [
|
|
{
|
|
"model": "deepseek/deepseek-coder-v2",
|
|
"api_key": "${DEEPSEEK_API_KEY}",
|
|
"base_url": "https://api.deepseek.com/v1"
|
|
},
|
|
{
|
|
"model": "gpt-4o",
|
|
"api_key": "${OPENAI_API_KEY}",
|
|
"base_url": "https://api.openai.com/v1"
|
|
}
|
|
],
|
|
|
|
"LLM_TIMEOUT": 60,
|
|
"LLM_RETRY_COUNT": 3
|
|
}
|
|
```
|
|
|
|
**Verify API keys are loaded:**
|
|
```bash
|
|
cat /home/bam/openhands/.env
|
|
# Should contain:
|
|
# MINIMAX_API_KEY=xxx
|
|
# DEEPSEEK_API_KEY=xxx
|
|
# OPENAI_API_KEY=xxx (optional backup)
|
|
```
|
|
|
|
**Note:** Exact config format may vary. Check OpenHands documentation or existing settings.json structure. The systemd service will load these env vars automatically.
|
|
|
|
**Restart OpenHands to apply:**
|
|
```bash
|
|
sudo systemctl restart openhands.service
|
|
sudo systemctl status openhands.service
|
|
```
|
|
|
|
---
|
|
|
|
### Step 2: Discover API Endpoints (15 min)
|
|
|
|
**Goal:** Find available API endpoints for triggering tasks
|
|
|
|
**Check OpenHands documentation:**
|
|
```bash
|
|
# Look for API docs in help
|
|
/home/bam/.local/bin/openhands serve --help
|
|
|
|
# Or check if web UI exposes API docs:
|
|
# Visit: http://10.10.10.11:3000/docs
|
|
# Or: http://10.10.10.11:3000/api/docs
|
|
```
|
|
|
|
**Expected endpoints (typical OpenHands API):**
|
|
```
|
|
POST /api/sessions # Create new session
|
|
POST /api/sessions/{id}/messages # Send task message
|
|
GET /api/sessions/{id} # Get session status
|
|
GET /api/sessions/{id}/events # Get execution events
|
|
```
|
|
|
|
**Test manually:**
|
|
```bash
|
|
# Create session
|
|
curl -X POST http://localhost:3000/api/sessions \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"workspace": "/home/bam/workspace",
|
|
"model": "openai/MiniMax-M2",
|
|
"api_key": "your_minimax_key"
|
|
}'
|
|
|
|
# Response should include session_id
|
|
```
|
|
|
|
**If API endpoints unclear:**
|
|
- Check OpenHands GitHub docs
|
|
- Inspect network requests in web UI (browser DevTools)
|
|
- Look for OpenAPI/Swagger spec
|
|
|
|
---
|
|
|
|
### Step 3: Create n8n → OpenHands API Workflow (45 min)
|
|
|
|
**Goal:** Build n8n workflow that calls OpenHands API
|
|
|
|
#### Workflow Design:
|
|
```
|
|
[1] Manual Trigger (for testing)
|
|
↓
|
|
[2] HTTP Request - Create Session
|
|
→ POST /api/sessions
|
|
→ Save session_id
|
|
↓
|
|
[3] HTTP Request - Send Task
|
|
→ POST /api/sessions/{session_id}/messages
|
|
→ Body: { "task": "Create file test.txt" }
|
|
↓
|
|
[4] Wait 5 seconds
|
|
↓
|
|
[5] HTTP Request - Get Status (loop until done)
|
|
→ GET /api/sessions/{session_id}
|
|
→ Check if "status": "completed"
|
|
↓
|
|
[6] If Node - Check Success
|
|
├─ TRUE → [7] Get Results
|
|
└─ FALSE → [8] Error Handler
|
|
```
|
|
|
|
#### n8n Configuration:
|
|
|
|
**Node 1: Manual Trigger**
|
|
- Just add it, no config
|
|
|
|
**Node 2: HTTP Request - Create Session**
|
|
```
|
|
Method: POST
|
|
URL: http://127.0.0.1:3000/api/sessions
|
|
Headers:
|
|
Content-Type: application/json
|
|
Body:
|
|
{
|
|
"workspace": "/home/bam/workspace",
|
|
"model": "openai/MiniMax-M2",
|
|
"api_key": "{{$env.MINIMAX_API_KEY}}"
|
|
}
|
|
|
|
Options:
|
|
Response Format: JSON
|
|
```
|
|
|
|
**Node 3: HTTP Request - Send Task**
|
|
```
|
|
Method: POST
|
|
URL: http://127.0.0.1:3000/api/sessions/{{ $json.session_id }}/messages
|
|
Body:
|
|
{
|
|
"task": "Create a file named test.txt with content: Hello from n8n API!"
|
|
}
|
|
```
|
|
|
|
**Node 4: Wait Node**
|
|
```
|
|
Time: 5 seconds
|
|
```
|
|
|
|
**Node 5: HTTP Request - Get Status**
|
|
```
|
|
Method: GET
|
|
URL: http://127.0.0.1:3000/api/sessions/{{ $node["HTTP Request"].json.session_id }}
|
|
|
|
# May need to loop this until status is "completed"
|
|
# Use n8n Loop node if available
|
|
```
|
|
|
|
**Node 6: SSH - Verify File Created**
|
|
```
|
|
Credentials: ai-dev-localhost
|
|
Command: cat /home/bam/workspace/test.txt
|
|
```
|
|
|
|
#### Test Workflow:
|
|
1. Execute manually
|
|
2. Check each node output
|
|
3. Verify file created in /home/bam/workspace/
|
|
|
|
---
|
|
|
|
### Step 4: Gitea Webhook Integration (30 min)
|
|
|
|
**Goal:** Trigger n8n workflow on git push
|
|
|
|
#### In Gitea (https://git.oky.sh):
|
|
1. Create test repository: `test-project`
|
|
2. Go to Settings → Webhooks → Add Webhook → Gitea
|
|
3. Configure:
|
|
```
|
|
Target URL: https://n8n.oky.sh/webhook/gitea-push
|
|
HTTP Method: POST
|
|
Content Type: application/json
|
|
Secret: [generate random string]
|
|
Trigger On: Push events
|
|
Active: ✓
|
|
```
|
|
4. Test webhook
|
|
|
|
#### In n8n:
|
|
1. Replace Manual Trigger with Webhook Trigger
|
|
2. Configure:
|
|
```
|
|
Webhook URLs:
|
|
Production: https://n8n.oky.sh/webhook/gitea-push
|
|
|
|
HTTP Method: POST
|
|
|
|
Authentication: Header Auth
|
|
Name: X-Gitea-Signature
|
|
Value: [your secret from Gitea]
|
|
|
|
Response:
|
|
Mode: Last Node
|
|
Code: 200
|
|
```
|
|
|
|
3. Extract data:
|
|
```
|
|
Repository: {{ $json.repository.full_name }}
|
|
Commit: {{ $json.commits[0].message }}
|
|
Branch: {{ $json.ref }}
|
|
```
|
|
|
|
4. Pass to OpenHands:
|
|
```
|
|
Task: "Build and test project {{ $json.repository.full_name }} on commit {{ $json.after }}"
|
|
Workspace: "/home/bam/workspace/{{ $json.repository.name }}"
|
|
```
|
|
|
|
#### Test:
|
|
```bash
|
|
# In test-project repo
|
|
echo "Test" > README.md
|
|
git add .
|
|
git commit -m "Test webhook"
|
|
git push origin main
|
|
|
|
# Check n8n workflow executes
|
|
# Check OpenHands builds project
|
|
```
|
|
|
|
---
|
|
|
|
### Step 5: Build Workflow with Retry Logic (1-2 hours)
|
|
|
|
**Goal:** Production-ready workflow with error handling
|
|
|
|
#### Enhanced Workflow:
|
|
```
|
|
[1] Webhook Trigger (Gitea push)
|
|
↓
|
|
[2] Extract Repo Info
|
|
↓
|
|
[3] Clone/Update Repository (SSH)
|
|
→ git clone or git pull
|
|
↓
|
|
[4] Create OpenHands Session
|
|
↓
|
|
[5] Send Build Task
|
|
→ Task: "Run npm install, npm test, npm build"
|
|
↓
|
|
[6] Poll Status (Loop)
|
|
→ Check every 10s
|
|
→ Timeout: 5 minutes
|
|
↓
|
|
[7] If Node - Build Success?
|
|
├─ YES → [8] Success Notification
|
|
│ └─ Update commit status ✅
|
|
│
|
|
└─ NO → [9] Get Error Details
|
|
↓
|
|
[10] Send Feedback to OpenHands
|
|
→ "Build failed with: {error}, please fix"
|
|
↓
|
|
[11] Retry Counter (max 3)
|
|
├─ < 3 → Back to [5]
|
|
└─ ≥ 3 → [12] Final Failure Notification
|
|
```
|
|
|
|
#### Key Components:
|
|
|
|
**Clone Repository Node (SSH):**
|
|
```bash
|
|
cd /home/bam/workspace
|
|
if [ -d "{{ $json.repo_name }}" ]; then
|
|
cd {{ $json.repo_name }} && git pull
|
|
else
|
|
git clone {{ $json.clone_url }}
|
|
fi
|
|
```
|
|
|
|
**Build Task (to OpenHands):**
|
|
```json
|
|
{
|
|
"task": "Navigate to /home/bam/workspace/{{ $json.repo_name }} and run: npm install && npm test && npm build. Report any errors.",
|
|
"workspace": "/home/bam/workspace/{{ $json.repo_name }}",
|
|
"max_iterations": 20
|
|
}
|
|
```
|
|
|
|
**Retry Logic (n8n Function Node):**
|
|
```javascript
|
|
// Get retry count from workflow static data
|
|
const retries = $workflow.staticData.retry_count || 0;
|
|
|
|
if (retries >= 3) {
|
|
return {
|
|
action: 'fail',
|
|
message: 'Max retries exceeded'
|
|
};
|
|
}
|
|
|
|
// Increment retry
|
|
$workflow.staticData.retry_count = retries + 1;
|
|
|
|
return {
|
|
action: 'retry',
|
|
attempt: retries + 1,
|
|
feedback: $json.error_message
|
|
};
|
|
```
|
|
|
|
**Success Notification (HTTP to Gitea API):**
|
|
```
|
|
POST https://git.oky.sh/api/v1/repos/{{ $json.repo }}/statuses/{{ $json.commit_sha }}
|
|
Authorization: token YOUR_GITEA_TOKEN
|
|
Body:
|
|
{
|
|
"state": "success",
|
|
"description": "Build passed",
|
|
"context": "openhands/build"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 TESTING CHECKLIST
|
|
|
|
### Integration Tests:
|
|
|
|
- [ ] OpenHands server starts and responds
|
|
- [ ] API creates sessions successfully
|
|
- [ ] API accepts and executes tasks
|
|
- [ ] Tasks complete and return results
|
|
- [ ] n8n can call all API endpoints
|
|
- [ ] Webhook receives Gitea events
|
|
- [ ] Repository clones correctly
|
|
- [ ] Build task executes
|
|
- [ ] Success path works end-to-end
|
|
- [ ] Failure triggers retry
|
|
- [ ] Max retries stops infinite loop
|
|
- [ ] Notifications sent correctly
|
|
|
|
### Error Scenarios:
|
|
|
|
- [ ] Invalid API request
|
|
- [ ] OpenHands timeout
|
|
- [ ] Build failure (syntax error)
|
|
- [ ] Network issues
|
|
- [ ] Git clone failure
|
|
- [ ] Webhook auth failure
|
|
|
|
---
|
|
|
|
## 📋 TROUBLESHOOTING
|
|
|
|
### OpenHands Server Won't Start:
|
|
|
|
```bash
|
|
# Check if port in use
|
|
sudo netstat -tulpn | grep 3000
|
|
|
|
# Check OpenHands logs
|
|
sudo journalctl -u openhands.service -n 50
|
|
|
|
# Try manual start to see errors
|
|
/home/bam/.local/bin/openhands serve
|
|
```
|
|
|
|
### API Endpoints Not Found:
|
|
|
|
```bash
|
|
# Check OpenHands version
|
|
/home/bam/.local/bin/openhands --version
|
|
|
|
# May need to update
|
|
pipx upgrade openhands-ai
|
|
|
|
# Or reinstall
|
|
pipx uninstall openhands-ai
|
|
pipx install openhands-ai
|
|
```
|
|
|
|
### n8n Cannot Reach OpenHands:
|
|
|
|
```bash
|
|
# Test from n8n container
|
|
docker exec -it n8n curl http://host.docker.internal:3000
|
|
|
|
# If fails, check if n8n has host.docker.internal access
|
|
# May need to add to docker-compose:
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway"
|
|
```
|
|
|
|
### Webhook Not Triggering:
|
|
|
|
```bash
|
|
# Check n8n webhook URL is accessible
|
|
curl https://n8n.oky.sh/webhook/gitea-push
|
|
|
|
# Check Gitea webhook logs:
|
|
# Gitea UI → Repository → Settings → Webhooks → Recent Deliveries
|
|
|
|
# Test with manual webhook trigger in Gitea UI
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 SUCCESS CRITERIA
|
|
|
|
**Phase 2 Complete When:**
|
|
1. ✅ OpenHands server running persistently
|
|
2. ✅ n8n can create sessions via API
|
|
3. ✅ Simple test task executes successfully
|
|
4. ✅ Gitea webhook triggers n8n workflow
|
|
5. ✅ End-to-end: Push → Build → Success/Fail
|
|
|
|
**Phase 3 Complete When:**
|
|
1. ✅ Retry logic working (max 3 attempts)
|
|
2. ✅ Error feedback to OpenHands
|
|
3. ✅ Commit status updates in Gitea
|
|
4. ✅ Tested with real project build
|
|
|
|
---
|
|
|
|
## 📚 REFERENCE COMMANDS
|
|
|
|
### Quick Status Check:
|
|
```bash
|
|
# All services status
|
|
cd /home/bam/services-stack && docker compose ps
|
|
|
|
# OpenHands server
|
|
sudo systemctl status openhands.service
|
|
|
|
# Check OpenHands API
|
|
curl http://localhost:3000/
|
|
|
|
# n8n workflows
|
|
curl -u admin:password https://n8n.oky.sh/api/v1/workflows
|
|
```
|
|
|
|
### Restart Services:
|
|
```bash
|
|
# Restart all Docker services
|
|
cd /home/bam/services-stack
|
|
docker compose restart
|
|
|
|
# Restart OpenHands only
|
|
sudo systemctl restart openhands.service
|
|
|
|
# Restart n8n only
|
|
docker compose restart n8n
|
|
```
|
|
|
|
### View Logs:
|
|
```bash
|
|
# OpenHands logs
|
|
sudo journalctl -u openhands.service -f
|
|
|
|
# n8n logs
|
|
docker logs -f n8n
|
|
|
|
# Caddy logs
|
|
docker logs -f caddy
|
|
|
|
# Gitea logs
|
|
docker logs -f gitea
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 CREDENTIALS REFERENCE
|
|
|
|
### n8n Login:
|
|
- URL: https://n8n.oky.sh
|
|
- User: admin (owner account)
|
|
- Password: [set during setup]
|
|
|
|
### Gitea Login:
|
|
- URL: https://git.oky.sh
|
|
- User: [admin account]
|
|
- Password: [set during setup]
|
|
|
|
### API Keys:
|
|
- MiniMax: `/home/bam/openhands/.env`
|
|
- SSH Key: `/home/bam/.ssh/n8n_key`
|
|
|
|
---
|
|
|
|
## ⏱️ ESTIMATED TIME BREAKDOWN
|
|
|
|
- Step 1: OpenHands Server Setup: **15 min**
|
|
- Step 1.5: Backup LLM Configuration: **10 min**
|
|
- Step 2: API Discovery: **15 min**
|
|
- Step 3: n8n API Workflow: **45 min**
|
|
- Step 4: Gitea Webhook: **30 min**
|
|
- Step 5: Retry Logic: **1-2 hours**
|
|
- Testing & Debugging: **30 min**
|
|
|
|
**Total: 3-4 hours**
|
|
|
|
---
|
|
|
|
## 🚀 READY TO START?
|
|
|
|
**Pre-flight Checklist:**
|
|
- [ ] All services running (docker compose ps)
|
|
- [ ] Can access Gitea (https://git.oky.sh)
|
|
- [ ] Can access n8n (https://n8n.oky.sh)
|
|
- [ ] SSH to ai-dev-node working
|
|
- [ ] Fresh terminal session
|
|
|
|
**First Command:**
|
|
```bash
|
|
/home/bam/.local/bin/openhands serve
|
|
```
|
|
|
|
If starts successfully → proceed to Step 1 systemd service!
|
|
If error → investigate OpenHands CLI installation
|
|
|
|
---
|
|
|
|
## 📝 NOTES
|
|
|
|
- **Port 3000:** OpenHands serve uses port 3000 (not configurable in CLI v1.3.0)
|
|
- **Note:** This conflicts with Gitea's internal port 3000, but OK since Gitea exposed as 3333
|
|
- OpenHands API: http://localhost:3000 (localhost only)
|
|
- n8n will access via http://host.docker.internal:3000 from container
|
|
- **API Mode vs Headless:** API is more reliable for automation
|
|
- **Persistence:** systemd service ensures OpenHands survives reboots
|
|
- **Security:** OpenHands API on localhost only (127.0.0.1)
|
|
- **Scaling:** Can add more OpenHands instances later
|
|
- **LLM Fallback:** MiniMax M2 → DeepSeek V2 → OpenAI GPT-4o (if configured)
|
|
|
|
**Good luck!** 🎯
|