openhands cli aproach
This commit is contained in:
parent
3db5b22c59
commit
c7e2c7ab0b
|
|
@ -0,0 +1,128 @@
|
||||||
|
# OpenHands Integration - Next Steps
|
||||||
|
|
||||||
|
## Status Summary
|
||||||
|
|
||||||
|
✅ **Completed:**
|
||||||
|
- Tested both API and CLI approaches
|
||||||
|
- Identified technical blockers (network namespace + TTY issues)
|
||||||
|
- Created 3 n8n workflow configurations
|
||||||
|
- Built Python wrapper scripts
|
||||||
|
- Comprehensive documentation
|
||||||
|
|
||||||
|
⏳ **Ready for Testing:**
|
||||||
|
- `/home/bam/openhands-pty.py` - Pseudo-TTY wrapper (needs verification)
|
||||||
|
- `/home/bam/claude/mvp-factory/openhands-n8n-workflow.json` - Complete workflow
|
||||||
|
|
||||||
|
## Immediate Actions Required
|
||||||
|
|
||||||
|
### 1. Test the pty-based wrapper (CRITICAL)
|
||||||
|
```bash
|
||||||
|
# Run this manually to verify it works:
|
||||||
|
python3 /home/bam/openhands-pty.py "Create a file named final-test.txt with content: Success!"
|
||||||
|
|
||||||
|
# Check if file was created:
|
||||||
|
ls -la /home/bam/final-test.txt
|
||||||
|
cat /home/bam/final-test.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. If wrapper works, proceed with n8n integration
|
||||||
|
```bash
|
||||||
|
# The workflow file to use:
|
||||||
|
/home/bam/claude/mvp-factory/openhands-n8n-workflow.json
|
||||||
|
|
||||||
|
# Import via n8n UI:
|
||||||
|
# 1. Open https://n8n.oky.sh
|
||||||
|
# 2. Credentials → Add SSH credentials (ai-dev-localhost)
|
||||||
|
# 3. Import from file → Select openhands-n8n-workflow.json
|
||||||
|
# 4. Activate workflow
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Test webhook endpoint
|
||||||
|
```bash
|
||||||
|
# Test manually:
|
||||||
|
curl -X POST https://n8n.oky.sh/webhook/openhands-task \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"repository": {"full_name": "test/repo"},
|
||||||
|
"commits": [{"message": "Test build task"}]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files Reference
|
||||||
|
|
||||||
|
**Python Wrappers:**
|
||||||
|
- `/home/bam/run-openhands.py` - Original wrapper (may have TTY issues)
|
||||||
|
- `/home/bam/openhands-pty.py` - **BEST CANDIDATE** (uses pseudo-TTY)
|
||||||
|
|
||||||
|
**n8n Workflows:**
|
||||||
|
- `/home/bam/claude/mvp-factory/openhands-n8n-workflow.json` - **USE THIS** (complete workflow)
|
||||||
|
- `/home/bam/claude/mvp-factory/openhands-cli-tmux-workflow.json` - Alternative with tmux
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- `/home/bam/claude/mvp-factory/OPENHANDS_INTEGRATION_STATUS.md` - Full status report
|
||||||
|
- `/home/bam/claude/mvp-factory/NEXT_STEPS.md` - This file
|
||||||
|
|
||||||
|
## If pty wrapper doesn't work:
|
||||||
|
|
||||||
|
**Option A: Debug and improve**
|
||||||
|
- Check logs from pty wrapper run
|
||||||
|
- Adjust timing in openhands-pty.py
|
||||||
|
- Try pexpect library if available
|
||||||
|
|
||||||
|
**Option B: Use tmux approach**
|
||||||
|
- Update n8n workflow to use tmux commands
|
||||||
|
- More reliable for long-running tasks
|
||||||
|
|
||||||
|
**Option C: API approach with fixed runtime**
|
||||||
|
- Debug network namespace issue
|
||||||
|
- Requires Docker networking expertise
|
||||||
|
- May take significant time
|
||||||
|
|
||||||
|
## Decision Matrix
|
||||||
|
|
||||||
|
| Approach | Reliability | Complexity | Time to Implement |
|
||||||
|
|----------|------------|------------|------------------|
|
||||||
|
| pty wrapper | Medium | Low | Immediate |
|
||||||
|
| tmux in n8n | High | Medium | 1-2 hours |
|
||||||
|
| Fixed API | High | High | Unknown |
|
||||||
|
| Manual CLI | N/A | High | Not viable |
|
||||||
|
|
||||||
|
## Gitea Webhook Configuration
|
||||||
|
|
||||||
|
Once n8n workflow works:
|
||||||
|
|
||||||
|
```
|
||||||
|
URL: https://n8n.oky.sh/webhook/openhands-task
|
||||||
|
Method: POST
|
||||||
|
Content-Type: application/json
|
||||||
|
Secret: [generate random string]
|
||||||
|
Events: Push events
|
||||||
|
```
|
||||||
|
|
||||||
|
Test by pushing to any repository:
|
||||||
|
```bash
|
||||||
|
echo "Test" > test.txt
|
||||||
|
git add . && git commit -m "Test webhook" && git push
|
||||||
|
```
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
- [ ] Python wrapper creates file successfully
|
||||||
|
- [ ] n8n workflow imports without errors
|
||||||
|
- [ ] Webhook triggers workflow
|
||||||
|
- [ ] OpenHands executes task
|
||||||
|
- [ ] File is created and verified
|
||||||
|
- [ ] End-to-end test passes
|
||||||
|
|
||||||
|
## Contact/Support
|
||||||
|
|
||||||
|
See `/home/bam/claude/mvp-factory/OPENHANDS_INTEGRATION_STATUS.md` for:
|
||||||
|
- Detailed error analysis
|
||||||
|
- Technical root causes
|
||||||
|
- Alternative solutions
|
||||||
|
- Complete testing procedures
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated:** 2025-11-30 22:07
|
||||||
|
**Ready for:** User testing and validation
|
||||||
|
|
@ -0,0 +1,422 @@
|
||||||
|
# OpenHands Integration Status Report
|
||||||
|
|
||||||
|
**Date:** 2025-11-30
|
||||||
|
**Phase:** OpenHands CLI Integration Testing
|
||||||
|
**Status:** Technical Blocker Identified
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Executive Summary
|
||||||
|
|
||||||
|
We attempted to integrate OpenHands with n8n workflows using both API and CLI approaches. While both methods show partial functionality, there are technical blockers preventing full automation:
|
||||||
|
|
||||||
|
1. **API Approach:** Conversations can be created, but runtime containers fail to start due to network namespace isolation
|
||||||
|
2. **CLI Approach:** Works interactively but requires TTY for auto-confirmation, which is problematic in non-TTY environments (like n8n SSH nodes)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What We Tested
|
||||||
|
|
||||||
|
### 1. OpenHands CLI Direct Execution
|
||||||
|
|
||||||
|
**Command:** `/home/bam/.local/bin/openhands -t "Create a file"`
|
||||||
|
|
||||||
|
**Result:**
|
||||||
|
- ✅ CLI starts successfully
|
||||||
|
- ✅ Agent initializes with MiniMax-M2 model
|
||||||
|
- ✅ Task is processed and action created
|
||||||
|
- ❌ **BLOCKER:** Waits for interactive confirmation ("Choose an option:")
|
||||||
|
- ❌ File not created in non-TTY environment
|
||||||
|
|
||||||
|
**Output Log:**
|
||||||
|
```
|
||||||
|
Predicted Security Risk: LOW
|
||||||
|
Agent Action created, waiting for confirmation
|
||||||
|
Choose an option:
|
||||||
|
Yes, proceed
|
||||||
|
Reject
|
||||||
|
Always proceed (don't ask again)
|
||||||
|
|
||||||
|
No input received; pausing agent.
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. OpenHands API Approach
|
||||||
|
|
||||||
|
**Test:** Create conversation via HTTP API
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/api/conversations \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"initial_user_msg": "Create a file"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Result:**
|
||||||
|
- ✅ Conversation created successfully (ID: a23d491e55ae4e0995b563a54705d59c)
|
||||||
|
- ❌ **BLOCKER:** Runtime stuck at "STATUS$STARTING_RUNTIME"
|
||||||
|
- ❌ Network namespace isolation prevents runtime container from connecting
|
||||||
|
|
||||||
|
**Status Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "STARTING",
|
||||||
|
"runtime_status": "STATUS$STARTING_RUNTIME",
|
||||||
|
"conversation_id": "a23d491e55ae4e0995b563a54705d59c"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. CLI Automation Attempts
|
||||||
|
|
||||||
|
#### Attempt 1: Python Wrapper (subprocess.PIPE)
|
||||||
|
**File:** `/home/bam/run-openhands.py`
|
||||||
|
|
||||||
|
**Result:**
|
||||||
|
- Created wrapper with stdin pipe
|
||||||
|
- Still receives TTY warning: "Warning: Input is not a terminal (fd=0)"
|
||||||
|
- Auto-confirmation logic attempted but unreliable
|
||||||
|
|
||||||
|
#### Attempt 2: Bash Script with Timeout
|
||||||
|
**File:** `/home/bam/test-openhands-cli.sh`
|
||||||
|
|
||||||
|
**Result:**
|
||||||
|
- Uses piped input: `echo -e "task\ny" | openhands -t ""`
|
||||||
|
- ❌ Input not properly received
|
||||||
|
- Task starts but never completes
|
||||||
|
|
||||||
|
#### Attempt 3: Python with pty Module
|
||||||
|
**File:** `/home/bam/openhands-pty.py`
|
||||||
|
|
||||||
|
**Result:**
|
||||||
|
- Created pseudo-TTY for proper terminal emulation
|
||||||
|
- Uses select() for async I/O
|
||||||
|
- ⏳ Still running during test (potential solution)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## n8n Workflows Created
|
||||||
|
|
||||||
|
We created three n8n workflow configurations:
|
||||||
|
|
||||||
|
### 1. Simple CLI Workflow
|
||||||
|
**File:** `/home/bam/claude/mvp-factory/openhands-cli-simple.json`
|
||||||
|
- Single SSH node
|
||||||
|
- Direct CLI execution
|
||||||
|
- Expected to fail due to TTY issues
|
||||||
|
|
||||||
|
### 2. tmux-based Workflow
|
||||||
|
**File:** `/home/bam/claude/mvp-factory/openhands-cli-tmux-workflow.json`
|
||||||
|
- Uses tmux for session management
|
||||||
|
- Attempts to run CLI in persistent session
|
||||||
|
- May work but untested
|
||||||
|
|
||||||
|
### 3. Complete Workflow with Webhook
|
||||||
|
**File:** `/home/bam/claude/mvp-factory/openhands-n8n-workflow.json`
|
||||||
|
- Webhook trigger for Gitea integration
|
||||||
|
- SSH execution node
|
||||||
|
- Verification node
|
||||||
|
- Response node
|
||||||
|
- **BEST CANDIDATE** for testing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Root Cause Analysis
|
||||||
|
|
||||||
|
### Network Namespace Isolation Issue
|
||||||
|
|
||||||
|
**Problem:** OpenHands server runs on host network, but runtime containers are in bridge network. The `--add-host host.docker.internal:host-gateway` flag resolves DNS but not port connectivity.
|
||||||
|
|
||||||
|
**Evidence:**
|
||||||
|
- API responds on http://localhost:3000
|
||||||
|
- Conversation creation succeeds
|
||||||
|
- Runtime startup fails silently
|
||||||
|
- Status remains "STATUS$STARTING_RUNTIME"
|
||||||
|
|
||||||
|
### TTY/Interactive Input Issue
|
||||||
|
|
||||||
|
**Problem:** OpenHands CLI requires interactive confirmation for security, but n8n SSH nodes don't provide TTY.
|
||||||
|
|
||||||
|
**Evidence:**
|
||||||
|
- "Warning: Input is not a terminal (fd=0)"
|
||||||
|
- "Choose an option:" prompt appears
|
||||||
|
- Piped input not properly handled
|
||||||
|
- Auto-confirmation doesn't trigger
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Potential Solutions
|
||||||
|
|
||||||
|
### Solution 1: Improve Python Wrapper
|
||||||
|
**Approach:** Enhance `/home/bam/run-openhands.py` or `/home/bam/openhands-pty.py`
|
||||||
|
|
||||||
|
**Implementation:**
|
||||||
|
- Use pexpect library (if available) for robust interaction
|
||||||
|
- Implement proper response timing
|
||||||
|
- Add retry logic
|
||||||
|
- Test thoroughly
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- Works within existing setup
|
||||||
|
- No infrastructure changes
|
||||||
|
- Reusable for other automation
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- Requires Python library installation
|
||||||
|
- May still have timing issues
|
||||||
|
|
||||||
|
### Solution 2: Use tmux in n8n
|
||||||
|
**Approach:** Use tmux for persistent sessions in SSH node
|
||||||
|
|
||||||
|
**Implementation:**
|
||||||
|
```bash
|
||||||
|
tmux new-session -d -s task
|
||||||
|
tmux send-keys -t task 'openhands -t "task"' C-m
|
||||||
|
sleep 30
|
||||||
|
tmux capture-pane -t task -p
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- Provides proper TTY
|
||||||
|
- Industry-standard approach
|
||||||
|
- Works with existing SSH
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- Adds session management complexity
|
||||||
|
- Requires tmux on target system
|
||||||
|
- May timeout on long tasks
|
||||||
|
|
||||||
|
### Solution 3: Use OpenHands Built-in Automation
|
||||||
|
**Approach:** Check if OpenHands has non-interactive or batch mode
|
||||||
|
|
||||||
|
**Commands to check:**
|
||||||
|
```bash
|
||||||
|
openhands --help
|
||||||
|
openhands -h
|
||||||
|
cat ~/.openhands/settings.json
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- Official solution
|
||||||
|
- Most reliable
|
||||||
|
- Supported by upstream
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- May not exist in current version (1.3.0)
|
||||||
|
|
||||||
|
### Solution 4: API with Fixed Runtime
|
||||||
|
**Approach:** Fix network namespace issue for API approach
|
||||||
|
|
||||||
|
**Implementation:**
|
||||||
|
- Use host networking for runtime (dangerous)
|
||||||
|
- Custom Docker network configuration
|
||||||
|
- Different runtime architecture
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- Clean API interface
|
||||||
|
- Better error handling
|
||||||
|
- Proper status monitoring
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- Requires significant infrastructure changes
|
||||||
|
- Security implications
|
||||||
|
- May break other functionality
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current Workflow Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Gitea Push → n8n Webhook → SSH Node → OpenHands CLI → File Creation
|
||||||
|
↓
|
||||||
|
Verification Node
|
||||||
|
↓
|
||||||
|
Response to Gitea (optional)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Webhooks:**
|
||||||
|
- Gitea → https://n8n.oky.sh/webhook/openhands-task
|
||||||
|
- n8n will execute OpenHands task
|
||||||
|
- Verify file creation
|
||||||
|
- Return status to Gitea (future enhancement)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Immediate Next Steps
|
||||||
|
|
||||||
|
### Option 1: Continue with CLI Approach (Recommended)
|
||||||
|
1. Test the `openhands-pty.py` wrapper more thoroughly
|
||||||
|
2. If it works, update n8n workflow to use it
|
||||||
|
3. Test with real Gitea webhook
|
||||||
|
4. Add error handling and timeouts
|
||||||
|
|
||||||
|
### Option 2: Debug API Runtime Issue
|
||||||
|
1. Check Docker logs for runtime startup errors
|
||||||
|
2. Test network connectivity between containers
|
||||||
|
3. Try different Docker networking modes
|
||||||
|
4. If fixed, use API approach (cleaner)
|
||||||
|
|
||||||
|
### Option 3: Hybrid Approach
|
||||||
|
1. Use API to create conversation
|
||||||
|
2. Use CLI to execute task
|
||||||
|
3. Monitor status via API
|
||||||
|
4. Best of both worlds?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
```
|
||||||
|
/home/bam/
|
||||||
|
├── run-openhands.py # Python wrapper (original)
|
||||||
|
├── openhands-pty.py # Python wrapper with pty
|
||||||
|
├── test-openhands-cli.sh # Bash test script
|
||||||
|
├── start-openhands-fixed.sh # Docker startup script
|
||||||
|
└── claude/mvp-factory/
|
||||||
|
├── openhands-cli-simple.json # Simple workflow
|
||||||
|
├── openhands-cli-tmux-workflow.json # tmux-based workflow
|
||||||
|
├── openhands-n8n-workflow.json # Complete workflow
|
||||||
|
└── OPENHANDS_INTEGRATION_STATUS.md # This file
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Required
|
||||||
|
|
||||||
|
### Pre-Production Testing
|
||||||
|
|
||||||
|
1. **Wrapper Script Testing**
|
||||||
|
- [ ] Test `/home/bam/openhands-pty.py` with simple task
|
||||||
|
- [ ] Verify file creation works
|
||||||
|
- [ ] Test timeout handling
|
||||||
|
- [ ] Test error handling
|
||||||
|
|
||||||
|
2. **n8n Workflow Testing**
|
||||||
|
- [ ] Import `/home/bam/claude/mvp-factory/openhands-n8n-workflow.json`
|
||||||
|
- [ ] Configure SSH credentials
|
||||||
|
- [ ] Test webhook manually
|
||||||
|
- [ ] Check execution logs
|
||||||
|
|
||||||
|
3. **End-to-End Testing**
|
||||||
|
- [ ] Configure Gitea webhook
|
||||||
|
- [ ] Push to test repository
|
||||||
|
- [ ] Verify workflow triggers
|
||||||
|
- [ ] Check OpenHands execution
|
||||||
|
- [ ] Verify file creation
|
||||||
|
|
||||||
|
4. **Integration Testing**
|
||||||
|
- [ ] Test with real project (not just file creation)
|
||||||
|
- [ ] Test npm install & build
|
||||||
|
- [ ] Test error scenarios
|
||||||
|
- [ ] Test timeout handling
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Risks and Considerations
|
||||||
|
|
||||||
|
### Security Risks
|
||||||
|
- OpenHands has sudo access in container
|
||||||
|
- SSH credentials stored in n8n
|
||||||
|
- Webhook endpoints exposed publicly
|
||||||
|
- Runtime isolation issues
|
||||||
|
|
||||||
|
### Reliability Risks
|
||||||
|
- TTY issues may prevent automation
|
||||||
|
- Network namespace problems
|
||||||
|
- Timeout handling inadequate
|
||||||
|
- No retry logic currently
|
||||||
|
|
||||||
|
### Operational Risks
|
||||||
|
- Long-running tasks in SSH node
|
||||||
|
- Session management complexity
|
||||||
|
- Log storage and rotation
|
||||||
|
- Resource consumption
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
To consider this integration complete:
|
||||||
|
|
||||||
|
1. ✅ OpenHands can be triggered via n8n
|
||||||
|
2. ✅ Task executes successfully (not just starts)
|
||||||
|
3. ✅ File/folder creation verified
|
||||||
|
4. ✅ Gitea webhook triggers workflow
|
||||||
|
5. ✅ End-to-end flow works (Push → Build → Verify)
|
||||||
|
6. ✅ Error handling and timeouts implemented
|
||||||
|
7. ✅ Documentation updated
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommendations
|
||||||
|
|
||||||
|
### Immediate (Today)
|
||||||
|
1. **Test `openhands-pty.py` thoroughly**
|
||||||
|
- If it works: Use in n8n workflow
|
||||||
|
- If not: Debug and improve
|
||||||
|
|
||||||
|
2. **Use `/home/bam/claude/mvp-factory/openhands-n8n-workflow.json`**
|
||||||
|
- Most complete workflow
|
||||||
|
- Ready for testing
|
||||||
|
- Good documentation
|
||||||
|
|
||||||
|
### Short-term (This Week)
|
||||||
|
1. **Fix remaining TTY/automation issues**
|
||||||
|
2. **Add proper error handling**
|
||||||
|
3. **Test with real build tasks**
|
||||||
|
4. **Configure Gitea webhook properly**
|
||||||
|
|
||||||
|
### Long-term
|
||||||
|
1. **Investigate API runtime fix**
|
||||||
|
2. **Add retry logic and timeouts**
|
||||||
|
3. **Implement proper status reporting**
|
||||||
|
4. **Add logging and monitoring**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
The OpenHands integration is **partially functional** but has **technical blockers** preventing full automation. Both API and CLI approaches work partially:
|
||||||
|
|
||||||
|
- **CLI:** Starts but doesn't complete due to TTY issues
|
||||||
|
- **API:** Creates conversations but runtime fails to start
|
||||||
|
|
||||||
|
**Next action:** Test the `openhands-pty.py` wrapper and if successful, integrate into n8n workflow for full automation testing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Appendix: Command Reference
|
||||||
|
|
||||||
|
### Test OpenHands CLI Directly
|
||||||
|
```bash
|
||||||
|
/home/bam/.local/bin/openhands -t "Create a test file"
|
||||||
|
# Press 'y' when prompted, then 'exit'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Python Wrapper
|
||||||
|
```bash
|
||||||
|
python3 /home/bam/run-openhands.py "Create a file"
|
||||||
|
# Or
|
||||||
|
python3 /home/bam/openhands-pty.py "Create a file"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test API Directly
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/api/conversations \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"initial_user_msg": "Create a file"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check n8n Workflows
|
||||||
|
```bash
|
||||||
|
curl -u admin:password https://n8n.oky.sh/api/v1/workflows
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitor OpenHands Server
|
||||||
|
```bash
|
||||||
|
docker logs -f openhands-app
|
||||||
|
# Or if running via systemd
|
||||||
|
sudo journalctl -u openhands.service -f
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**End of Report**
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
# Simple proxy to allow n8n (bridge network) to reach OpenHands (host network)
|
||||||
|
# This is a workaround for the iptables restriction
|
||||||
|
|
||||||
|
services:
|
||||||
|
openhands-proxy:
|
||||||
|
image: alpine/socat:latest
|
||||||
|
container_name: openhands-proxy
|
||||||
|
restart: unless-stopped
|
||||||
|
# Listen on port 3000 inside services-stack network
|
||||||
|
# Forward to host's port 3000 (OpenHands)
|
||||||
|
command: tcp-listen:3000,fork,reuseaddr tcp-connect:host.docker.internal:3000
|
||||||
|
networks:
|
||||||
|
- services-network
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
services-network:
|
||||||
|
name: services-stack_services-network
|
||||||
|
external: true
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"instanceId": "openhands-cli-test"
|
||||||
|
},
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"command": "echo 'Hello World' && /home/bam/.local/bin/openhands -t 'Create a file named test-cli.txt with content: Testing CLI workflow'",
|
||||||
|
"sessionId": "test-session"
|
||||||
|
},
|
||||||
|
"id": "ssh-execute",
|
||||||
|
"name": "Execute OpenHands CLI",
|
||||||
|
"type": "n8n-nodes-base.ssh",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [460, 300],
|
||||||
|
"credentials": {
|
||||||
|
"sshPassword": {
|
||||||
|
"id": "ai-dev-localhost",
|
||||||
|
"name": "ai-dev-localhost"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pinData": {},
|
||||||
|
"settings": {
|
||||||
|
"executionOrder": "v1"
|
||||||
|
},
|
||||||
|
"staticData": null,
|
||||||
|
"tags": [],
|
||||||
|
"triggerCount": 0,
|
||||||
|
"updatedAt": "2025-11-30T21:50:00.000Z",
|
||||||
|
"versionId": "1",
|
||||||
|
"active": false,
|
||||||
|
"meta": {
|
||||||
|
"templateCredsSetupCompleted": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"instanceId": "openhands-cli-tmux-test"
|
||||||
|
},
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"command": "cd /home/bam && tmux new-session -d -s openhands-task && tmux send-keys -t openhands-task 'python3 /home/bam/openhands-pty.py \"$TASK\"' C-m && sleep 60 && tmux capture-pane -t openhands-task -p",
|
||||||
|
"sessionId": "test-session"
|
||||||
|
},
|
||||||
|
"id": "ssh-execute",
|
||||||
|
"name": "Execute OpenHands CLI via tmux",
|
||||||
|
"type": "n8n-nodes-base.ssh",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [460, 300],
|
||||||
|
"credentials": {
|
||||||
|
"sshPassword": {
|
||||||
|
"id": "ai-dev-localhost",
|
||||||
|
"name": "ai-dev-localhost"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"command": "ls -la /home/bam/*.txt 2>/dev/null | tail -10",
|
||||||
|
"sessionId": "test-session"
|
||||||
|
},
|
||||||
|
"id": "ssh-verify",
|
||||||
|
"name": "Verify Files Created",
|
||||||
|
"type": "n8n-nodes-base.ssh",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [680, 300],
|
||||||
|
"credentials": {
|
||||||
|
"sshPassword": {
|
||||||
|
"id": "ai-dev-localhost",
|
||||||
|
"name": "ai-dev-localhost"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pinData": {},
|
||||||
|
"settings": {
|
||||||
|
"executionOrder": "v1"
|
||||||
|
},
|
||||||
|
"staticData": null,
|
||||||
|
"tags": [],
|
||||||
|
"triggerCount": 0,
|
||||||
|
"updatedAt": "2025-11-30T22:00:00.000Z",
|
||||||
|
"versionId": "1",
|
||||||
|
"active": false,
|
||||||
|
"meta": {
|
||||||
|
"templateCredsSetupCompleted": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"instanceId": "openhands-cli-test"
|
||||||
|
},
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"parameters": {},
|
||||||
|
"id": "webhook-trigger",
|
||||||
|
"name": "Webhook",
|
||||||
|
"type": "n8n-nodes-base.webhook",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [460, 300],
|
||||||
|
"webhookId": "gitea-webhook"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"command": "=cd /home/bam && echo \"{{ $json.repository.full_name }} {{ $json.commits[0].message }}\" > /tmp/task.txt && /home/bam/.local/bin/openhands -t \"$(cat /tmp/task.txt)\"",
|
||||||
|
"sessionId": "bam-openhands"
|
||||||
|
},
|
||||||
|
"id": "ssh-execute",
|
||||||
|
"name": "2. SSH Execute OpenHands",
|
||||||
|
"type": "n8n-nodes-base.ssh",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [680, 300],
|
||||||
|
"credentials": {
|
||||||
|
"sshPassword": {
|
||||||
|
"id": "ai-dev-localhost",
|
||||||
|
"name": "ai-dev-localhost"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"command": "=ls -la /home/bam/*.txt 2>/dev/null | tail -10",
|
||||||
|
"sessionId": "bam-openhands"
|
||||||
|
},
|
||||||
|
"id": "ssh-verify",
|
||||||
|
"name": "3. SSH Verify Results",
|
||||||
|
"type": "n8n-nodes-base.ssh",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [900, 300],
|
||||||
|
"credentials": {
|
||||||
|
"sshPassword": {
|
||||||
|
"id": "ai-dev-localhost",
|
||||||
|
"name": "ai-dev-localhost"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pinData": {},
|
||||||
|
"settings": {
|
||||||
|
"executionOrder": "v1"
|
||||||
|
},
|
||||||
|
"staticData": null,
|
||||||
|
"tags": [],
|
||||||
|
"triggerCount": 0,
|
||||||
|
"updatedAt": "2025-11-30T21:50:00.000Z",
|
||||||
|
"versionId": "1",
|
||||||
|
"active": false,
|
||||||
|
"meta": {
|
||||||
|
"templateCredsSetupCompleted": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"instanceId": "openhands-n8n-workflow"
|
||||||
|
},
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"httpMethod": "POST",
|
||||||
|
"path": "openhands-task",
|
||||||
|
"responseMode": "responseNode"
|
||||||
|
},
|
||||||
|
"id": "webhook",
|
||||||
|
"name": "Webhook Trigger",
|
||||||
|
"type": "n8n-nodes-base.webhook",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [240, 300],
|
||||||
|
"webhookId": "openhands-webhook"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"command": "cd /home/bam && echo \"{{ $json.repository.full_name }}: {{ $json.commits[0].message }}\" > /tmp/openhands-task.txt && python3 /home/bam/run-openhands.py \"$(cat /tmp/openhands-task.txt)\"",
|
||||||
|
"sessionId": "openhands-session"
|
||||||
|
},
|
||||||
|
"id": "ssh-execute",
|
||||||
|
"name": "Execute OpenHands",
|
||||||
|
"type": "n8n-nodes-base.ssh",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [460, 300],
|
||||||
|
"credentials": {
|
||||||
|
"sshPassword": {
|
||||||
|
"id": "ai-dev-localhost",
|
||||||
|
"name": "ai-dev-localhost"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"command": "ls -la /home/bam/*.txt 2>/dev/null | tail -15",
|
||||||
|
"sessionId": "openhands-session"
|
||||||
|
},
|
||||||
|
"id": "ssh-verify",
|
||||||
|
"name": "Verify Results",
|
||||||
|
"type": "n8n-nodes-base.ssh",
|
||||||
|
"typeVersion": 2,
|
||||||
|
"position": [680, 300],
|
||||||
|
"credentials": {
|
||||||
|
"sshPassword": {
|
||||||
|
"id": "ai-dev-localhost",
|
||||||
|
"name": "ai-dev-localhost"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"parameters": {
|
||||||
|
"respondWith": "json",
|
||||||
|
"responseBody": {
|
||||||
|
"status": "success",
|
||||||
|
"message": "OpenHands task executed",
|
||||||
|
"timestamp": "{{ $now }}",
|
||||||
|
"results": "Check logs for details"
|
||||||
|
},
|
||||||
|
"options": {}
|
||||||
|
},
|
||||||
|
"id": "webhook-response",
|
||||||
|
"name": "Webhook Response",
|
||||||
|
"type": "n8n-nodes-base.respondToWebhook",
|
||||||
|
"typeVersion": 1,
|
||||||
|
"position": [900, 300]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": {
|
||||||
|
"Webhook Trigger": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "Execute OpenHands",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Execute OpenHands": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "Verify Results",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Verify Results": {
|
||||||
|
"main": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"node": "Webhook Response",
|
||||||
|
"type": "main",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pinData": {},
|
||||||
|
"settings": {
|
||||||
|
"executionOrder": "v1"
|
||||||
|
},
|
||||||
|
"staticData": null,
|
||||||
|
"tags": [],
|
||||||
|
"triggerCount": 1,
|
||||||
|
"updatedAt": "2025-11-30T22:10:00.000Z",
|
||||||
|
"versionId": "1",
|
||||||
|
"active": false,
|
||||||
|
"meta": {
|
||||||
|
"templateCredsSetupCompleted": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"url": "http://10.10.10.11:3000/api/conversations",
|
"url": "http://host.docker.internal:3000/api/conversations",
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"sendBody": true,
|
"sendBody": true,
|
||||||
"bodyParameters": {
|
"bodyParameters": {
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"url": "=http://10.10.10.11:3000/api/conversations/{{ $json.conversation_id }}/start",
|
"url": "=http://host.docker.internal:3000/api/conversations/{{ $json.conversation_id }}/start",
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"sendBody": true,
|
"sendBody": true,
|
||||||
"specifyBody": "json",
|
"specifyBody": "json",
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"url": "=http://10.10.10.11:3000/api/conversations/{{ $('1. Create Conversation').item.json.conversation_id }}",
|
"url": "=http://host.docker.internal:3000/api/conversations/{{ $('1. Create Conversation').item.json.conversation_id }}",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"options": {
|
"options": {
|
||||||
"response": {
|
"response": {
|
||||||
|
|
@ -165,7 +165,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"url": "=http://10.10.10.11:3000/api/conversations/{{ $('1. Create Conversation').item.json.conversation_id }}/events",
|
"url": "=http://host.docker.internal:3000/api/conversations/{{ $('1. Create Conversation').item.json.conversation_id }}/events",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"options": {
|
"options": {
|
||||||
"response": {
|
"response": {
|
||||||
|
|
@ -361,5 +361,9 @@
|
||||||
"tags": [],
|
"tags": [],
|
||||||
"triggerCount": 0,
|
"triggerCount": 0,
|
||||||
"updatedAt": "2025-11-30T08:30:00.000Z",
|
"updatedAt": "2025-11-30T08:30:00.000Z",
|
||||||
"versionId": "1"
|
"versionId": "1",
|
||||||
|
"active": false,
|
||||||
|
"meta": {
|
||||||
|
"templateCredsSetupCompleted": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue