Merge pull request #2 from lfglabs-dev/feature/agent-tree
Feature/agent tree
This commit is contained in:
152
.cursor/rules/deployment.md
Normal file
152
.cursor/rules/deployment.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Open Agent - Deployment Guide
|
||||
|
||||
## Production Server
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Host** | `95.216.112.253` |
|
||||
| **SSH Access** | `ssh root@95.216.112.253` |
|
||||
| **Backend URL** | `https://agent-backend.thomas.md` |
|
||||
| **Dashboard URL** | `https://agent.thomas.md` (Vercel deployment) |
|
||||
| **Environment file** | `/etc/open_agent/open_agent.env` |
|
||||
| **Binary location** | `/usr/local/bin/open_agent` |
|
||||
| **Systemd service** | `open_agent` |
|
||||
| **Source code** | `/root/open_agent` |
|
||||
|
||||
## Port Configuration
|
||||
|
||||
| Service | Local Port | Production URL |
|
||||
|---------|-----------|----------------|
|
||||
| Backend API | 3000 | https://agent-backend.thomas.md |
|
||||
| Dashboard | 3001 | https://agent.thomas.md |
|
||||
|
||||
## Local Development
|
||||
|
||||
- **Backend API**: `http://127.0.0.1:3000` (Rust server via `cargo run`)
|
||||
- **Dashboard**: `http://127.0.0.1:3001` (Next.js via `bun run dev`)
|
||||
- **Environment files**:
|
||||
- Backend: `.env` in project root
|
||||
- Dashboard: `dashboard/.env.local`
|
||||
|
||||
## Common Operations
|
||||
|
||||
### Check Service Status
|
||||
```bash
|
||||
ssh root@95.216.112.253 'systemctl status open_agent'
|
||||
```
|
||||
|
||||
### View Logs
|
||||
```bash
|
||||
ssh root@95.216.112.253 'journalctl -u open_agent -f'
|
||||
```
|
||||
|
||||
### Restart Service
|
||||
```bash
|
||||
ssh root@95.216.112.253 'systemctl restart open_agent'
|
||||
```
|
||||
|
||||
### Edit Environment Variables
|
||||
```bash
|
||||
ssh root@95.216.112.253 'vim /etc/open_agent/open_agent.env'
|
||||
# Then restart:
|
||||
ssh root@95.216.112.253 'systemctl restart open_agent'
|
||||
```
|
||||
|
||||
## Full Redeployment
|
||||
|
||||
To redeploy from scratch:
|
||||
|
||||
```bash
|
||||
# 1. SSH into server
|
||||
ssh root@95.216.112.253
|
||||
|
||||
# 2. Go to source directory
|
||||
cd /root/open_agent
|
||||
|
||||
# 3. Pull latest changes
|
||||
git pull
|
||||
|
||||
# 4. Build release binary
|
||||
cargo build --release
|
||||
|
||||
# 5. Copy binary to /usr/local/bin
|
||||
cp target/release/open_agent /usr/local/bin/open_agent
|
||||
|
||||
# 6. Restart service
|
||||
systemctl restart open_agent
|
||||
|
||||
# 7. Check status
|
||||
systemctl status open_agent
|
||||
```
|
||||
|
||||
## SSH Key for Git Access
|
||||
|
||||
The VPS has a cursor SSH key at `~/.ssh/cursor` which has read access to private GitHub repositories. The git remote should be configured to use SSH:
|
||||
|
||||
```bash
|
||||
# Check remote URL
|
||||
git remote -v
|
||||
|
||||
# If needed, switch to SSH:
|
||||
git remote set-url origin git@github.com:owner/open_agent.git
|
||||
```
|
||||
|
||||
Make sure the SSH config uses the cursor key for github.com:
|
||||
|
||||
```bash
|
||||
# ~/.ssh/config on VPS
|
||||
Host github.com
|
||||
HostName github.com
|
||||
User git
|
||||
IdentityFile ~/.ssh/cursor
|
||||
```
|
||||
|
||||
## Systemd Service Configuration
|
||||
|
||||
The service file is typically at `/etc/systemd/system/open_agent.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Open Agent
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/root/open_agent
|
||||
EnvironmentFile=/etc/open_agent/open_agent.env
|
||||
ExecStart=/usr/local/bin/open_agent
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
## Nginx Reverse Proxy
|
||||
|
||||
The backend is proxied through nginx at `agent-backend.thomas.md`. The nginx config typically includes:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name agent-backend.thomas.md;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# SSL managed by certbot
|
||||
}
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- The API requires authentication when `DEV_MODE=false`
|
||||
- JWT tokens are used for dashboard authentication
|
||||
- Keep `.env` and `open_agent.env` out of version control
|
||||
- The agent has full machine access - be careful with what tasks you submit
|
||||
178
.cursorrules
178
.cursorrules
@@ -1,178 +0,0 @@
|
||||
# Open Agent - Cursor Rules & Project Philosophy
|
||||
|
||||
## Project Overview
|
||||
|
||||
Open Agent is a minimal autonomous coding agent implemented in Rust. It is designed to be:
|
||||
- **AI-maintainable**: Rust's strong type system and compiler provide immediate feedback
|
||||
- **Self-contained**: No external dependencies beyond OpenRouter for LLM access
|
||||
- **Full-access**: Has complete access to the local machine (filesystem, terminal, network)
|
||||
- **Provable**: Code structured for future formal verification in Lean
|
||||
|
||||
## Architecture (v2: Hierarchical Agent Tree)
|
||||
|
||||
### Agent Hierarchy
|
||||
```
|
||||
┌─────────────┐
|
||||
│ RootAgent │
|
||||
└──────┬──────┘
|
||||
┌─────────────────┼─────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌─────────────┐ ┌─────────────┐ ┌──────────┐
|
||||
│ Complexity │ │ Model │ │ Task │ │ Verifier │
|
||||
│ Estimator │ │ Selector │ │ Executor │ │ │
|
||||
└───────────────┘ └─────────────┘ └─────────────┘ └──────────┘
|
||||
```
|
||||
|
||||
### Agent Types
|
||||
|
||||
| Type | Role | Children |
|
||||
|------|------|----------|
|
||||
| **RootAgent** | Top-level orchestrator, receives API tasks | All leaf types |
|
||||
| **NodeAgent** | Intermediate orchestrator for subtasks | Executor, Verifier |
|
||||
| **ComplexityEstimator** | Estimates task difficulty (0-1 score) | None (leaf) |
|
||||
| **ModelSelector** | Picks optimal model (U-curve optimization) | None (leaf) |
|
||||
| **TaskExecutor** | Executes tasks using tools | None (leaf) |
|
||||
| **Verifier** | Validates completion (hybrid) | None (leaf) |
|
||||
|
||||
### Task Flow
|
||||
1. Receive task via HTTP API
|
||||
2. **Estimate Complexity** (ComplexityEstimator)
|
||||
3. If complex: **Split into subtasks** with budget allocation
|
||||
4. **Select Model** for each (sub)task (U-curve cost optimization)
|
||||
5. **Execute** using tools (TaskExecutor)
|
||||
6. **Verify** completion (Verifier: programmatic → LLM fallback)
|
||||
7. Aggregate results and return
|
||||
|
||||
### U-Curve Model Selection
|
||||
```
|
||||
Cost
|
||||
^
|
||||
| * *
|
||||
| * *
|
||||
| * * *
|
||||
| * * * *
|
||||
| * *
|
||||
+-------------------------> Model Capability
|
||||
(cheap/weak) (optimal) (expensive/strong)
|
||||
```
|
||||
- Cheap models: low per-token cost, high failure rate, more retries
|
||||
- Expensive models: high per-token cost, low failure rate
|
||||
- **Optimal**: minimizes expected total cost
|
||||
|
||||
## Module Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── agents/ # Hierarchical agent system
|
||||
│ ├── mod.rs # Agent traits (Agent, OrchestratorAgent, LeafAgent)
|
||||
│ ├── types.rs # AgentId, AgentType, AgentResult, Complexity
|
||||
│ ├── context.rs # Shared context for agent tree
|
||||
│ ├── tree.rs # Tree structure management
|
||||
│ ├── orchestrator/ # Orchestrator agents
|
||||
│ │ ├── root.rs # RootAgent (top-level)
|
||||
│ │ └── node.rs # NodeAgent (intermediate)
|
||||
│ └── leaf/ # Leaf agents (specialized workers)
|
||||
│ ├── complexity.rs # ComplexityEstimator
|
||||
│ ├── model_select.rs # ModelSelector with U-curve
|
||||
│ ├── executor.rs # TaskExecutor (tools in a loop)
|
||||
│ └── verifier.rs # Hybrid verification
|
||||
├── task/ # Task types with invariants
|
||||
│ ├── task.rs # Task, TaskId, TaskStatus
|
||||
│ ├── subtask.rs # Subtask, SubtaskPlan
|
||||
│ └── verification.rs # VerificationCriteria, ProgrammaticCheck
|
||||
├── budget/ # Cost tracking and pricing
|
||||
│ ├── budget.rs # Budget with spend/allocate invariants
|
||||
│ ├── pricing.rs # OpenRouter pricing client
|
||||
│ └── allocation.rs # Budget allocation strategies
|
||||
├── agent/ # Original simple agent (legacy)
|
||||
├── api/ # HTTP interface
|
||||
├── llm/ # LLM client (OpenRouter)
|
||||
├── tools/ # Tool implementations
|
||||
└── config.rs # Configuration
|
||||
```
|
||||
|
||||
## Design for Provability
|
||||
|
||||
### Conventions for Future Lean Proofs
|
||||
1. **Pre/Postconditions**: Document as `/// Precondition:` and `/// Postcondition:` comments
|
||||
2. **Invariants**: Document struct invariants, enforce in constructors
|
||||
3. **Algebraic Types**: Use enums with exhaustive matching, no `_` catch-all
|
||||
4. **Pure Functions**: Separate pure logic from IO where possible
|
||||
5. **Result Types**: Never panic, always return `Result`
|
||||
|
||||
### Example
|
||||
```rust
|
||||
/// Allocate budget for a subtask.
|
||||
///
|
||||
/// # Precondition
|
||||
/// `amount <= self.remaining_cents()`
|
||||
///
|
||||
/// # Postcondition
|
||||
/// `self.allocated_cents` increases by exactly `amount`
|
||||
pub fn allocate(&mut self, amount: u64) -> Result<(), BudgetError>
|
||||
```
|
||||
|
||||
## Adding a New Leaf Agent
|
||||
|
||||
1. Create `src/agents/leaf/your_agent.rs`
|
||||
2. Implement `Agent` trait:
|
||||
- `id()`, `agent_type()`, `execute()`
|
||||
3. Implement `LeafAgent` trait:
|
||||
- `capability()` → add variant to `LeafCapability` enum
|
||||
4. Register in `RootAgent::new()` or relevant orchestrator
|
||||
5. Document pre/postconditions for provability
|
||||
|
||||
## API Contract
|
||||
|
||||
```
|
||||
POST /api/task - Submit task (uses hierarchical agent)
|
||||
GET /api/task/{id} - Get task status and result
|
||||
GET /api/task/{id}/stream - Stream progress via SSE
|
||||
GET /api/health - Health check
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```
|
||||
OPENROUTER_API_KEY - Required. Your OpenRouter API key
|
||||
DEFAULT_MODEL - Optional. Default: openai/gpt-4.1-mini
|
||||
WORKSPACE_PATH - Optional. Default: current directory
|
||||
HOST - Optional. Default: 127.0.0.1
|
||||
PORT - Optional. Default: 3000
|
||||
MAX_ITERATIONS - Optional. Default: 50
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
### Production Server
|
||||
- **Host**: `95.216.112.253`
|
||||
- **SSH Access**: `ssh root@95.216.112.253` (key-based auth available to agent)
|
||||
- **Environment files**: Located in `/root/open_agent/.env` on the server
|
||||
|
||||
### Local Development
|
||||
- **Backend API**: `http://127.0.0.1:3000` (Rust server via `cargo run`)
|
||||
- **Dashboard**: `http://127.0.0.1:3001` (Next.js via `bun run dev`)
|
||||
- **Environment files**:
|
||||
- Backend: `.env` in project root
|
||||
- Dashboard: `dashboard/.env.local`
|
||||
|
||||
## Security Considerations
|
||||
|
||||
This agent has **full machine access**. It can:
|
||||
- Read/write any file the process can access
|
||||
- Execute any shell command
|
||||
- Make network requests
|
||||
|
||||
When deploying:
|
||||
- Run as a limited user
|
||||
- Use workspace isolation
|
||||
- Consider a sandbox for terminal commands
|
||||
- Never expose the API publicly without authentication
|
||||
|
||||
## Future Work
|
||||
|
||||
- [ ] Formal verification in Lean (extract pure logic)
|
||||
- [ ] WebSocket for bidirectional streaming
|
||||
- [ ] Semantic code search (embeddings-based)
|
||||
- [x] Multi-model support (U-curve optimization)
|
||||
- [x] Cost tracking (Budget system)
|
||||
Reference in New Issue
Block a user