219 lines
5.1 KiB
Bash
219 lines
5.1 KiB
Bash
#!/bin/bash
|
|
set -e
|
|
|
|
SKILLS_DIR="${SKILLS_DIR:-/skills}"
|
|
PERSONALITIES_DIR="${PERSONALITIES_DIR:-/personalities}"
|
|
WORKSPACES_DIR="${WORKSPACES_DIR:-/workspaces}"
|
|
AGENTS_DATA_DIR="${AGENTS_DATA_DIR:-/data/agents}"
|
|
|
|
# Install dependencies
|
|
install_deps() {
|
|
local needed=""
|
|
command -v socat &>/dev/null || needed="$needed socat"
|
|
command -v jq &>/dev/null || needed="$needed jq"
|
|
command -v sqlite3 &>/dev/null || needed="$needed sqlite3"
|
|
|
|
if [ -n "$needed" ]; then
|
|
echo "Installing dependencies:$needed"
|
|
apt-get update && apt-get install -y $needed
|
|
fi
|
|
}
|
|
|
|
# Setup directories
|
|
setup_dirs() {
|
|
mkdir -p "$PERSONALITIES_DIR"
|
|
mkdir -p "$WORKSPACES_DIR"
|
|
mkdir -p "$AGENTS_DATA_DIR"
|
|
mkdir -p /var/run/agents
|
|
|
|
echo "Personalities: $PERSONALITIES_DIR"
|
|
echo "Workspaces: $WORKSPACES_DIR"
|
|
echo "Data: $AGENTS_DATA_DIR"
|
|
}
|
|
|
|
# Detect storage backend
|
|
detect_storage() {
|
|
if [ -d "$SKILLS_DIR/postgres" ] && command -v psql &>/dev/null; then
|
|
echo "postgres"
|
|
elif [ -d "$SKILLS_DIR/duckdb" ] && command -v duckdb &>/dev/null; then
|
|
echo "duckdb"
|
|
else
|
|
echo "sqlite"
|
|
fi
|
|
}
|
|
|
|
# Initialize SQLite database (fallback)
|
|
init_sqlite() {
|
|
local db="$AGENTS_DATA_DIR/agents.db"
|
|
|
|
sqlite3 "$db" << 'SQL'
|
|
CREATE TABLE IF NOT EXISTS instances (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT,
|
|
personality TEXT NOT NULL,
|
|
workspace TEXT,
|
|
port INTEGER,
|
|
pid INTEGER,
|
|
status TEXT DEFAULT 'starting',
|
|
started_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
id TEXT PRIMARY KEY,
|
|
instance_id TEXT,
|
|
started_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
status TEXT DEFAULT 'active',
|
|
FOREIGN KEY (instance_id) REFERENCES instances(id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS messages (
|
|
id TEXT PRIMARY KEY,
|
|
conversation_id TEXT,
|
|
role TEXT,
|
|
content TEXT,
|
|
tool_calls TEXT,
|
|
timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (conversation_id) REFERENCES conversations(id)
|
|
);
|
|
SQL
|
|
|
|
echo "SQLite initialized: $db"
|
|
}
|
|
|
|
# Initialize DuckDB tables
|
|
init_duckdb() {
|
|
local db="$AGENTS_DATA_DIR/agents.duckdb"
|
|
|
|
duckdb "$db" << 'SQL'
|
|
CREATE TABLE IF NOT EXISTS instances (
|
|
id VARCHAR PRIMARY KEY,
|
|
name VARCHAR,
|
|
personality VARCHAR NOT NULL,
|
|
workspace VARCHAR,
|
|
port INTEGER,
|
|
pid INTEGER,
|
|
status VARCHAR DEFAULT 'starting',
|
|
started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
id VARCHAR PRIMARY KEY,
|
|
instance_id VARCHAR,
|
|
started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
status VARCHAR DEFAULT 'active'
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS messages (
|
|
id VARCHAR PRIMARY KEY,
|
|
conversation_id VARCHAR,
|
|
role VARCHAR,
|
|
content VARCHAR,
|
|
tool_calls JSON,
|
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
SQL
|
|
|
|
echo "DuckDB initialized: $db"
|
|
}
|
|
|
|
# Configure Caddy if present
|
|
configure_caddy() {
|
|
local caddy_dir="$SKILLS_DIR/caddy"
|
|
local agents_port="${AGENTS_PORT:-8800}"
|
|
local agents_domain="${AGENTS_DOMAIN:-}"
|
|
|
|
if [ ! -d "$caddy_dir" ]; then
|
|
echo "Caddy not found - Agents API on port $agents_port"
|
|
return 0
|
|
fi
|
|
|
|
echo "Caddy detected - configuring reverse proxy..."
|
|
mkdir -p "$caddy_dir/snippets.d"
|
|
|
|
local snippet="$caddy_dir/snippets.d/agents.caddy"
|
|
|
|
if [ -n "$agents_domain" ]; then
|
|
cat > "$snippet" << EOF
|
|
# Auto-generated by agents skill
|
|
$agents_domain {
|
|
reverse_proxy localhost:$agents_port
|
|
}
|
|
EOF
|
|
echo "Caddy config: $agents_domain -> localhost:$agents_port"
|
|
fi
|
|
}
|
|
|
|
# Create example personality if none exist
|
|
create_example_personality() {
|
|
if [ -d "$PERSONALITIES_DIR/orchestrator" ]; then
|
|
return 0
|
|
fi
|
|
|
|
echo "Creating example orchestrator personality..."
|
|
mkdir -p "$PERSONALITIES_DIR/orchestrator"
|
|
|
|
cat > "$PERSONALITIES_DIR/orchestrator/CLAUDE.md" << 'EOF'
|
|
# Orchestrator Agent
|
|
|
|
You are the orchestrator agent. Your role is to:
|
|
1. Understand high-level tasks
|
|
2. Break them into subtasks
|
|
3. Spawn specialist agents as needed
|
|
4. Coordinate their work
|
|
5. Synthesize results
|
|
|
|
## Spawning Agents
|
|
|
|
To spawn a specialist:
|
|
```bash
|
|
curl -X POST http://localhost:8800/instances \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"personality": "specialist-name", "workspace": "/workspaces/project"}'
|
|
```
|
|
|
|
## Available Personalities
|
|
|
|
Check what personalities are available:
|
|
```bash
|
|
curl http://localhost:8800/personalities
|
|
```
|
|
|
|
## Running Instances
|
|
|
|
Check what agents are running:
|
|
```bash
|
|
curl http://localhost:8800/instances
|
|
```
|
|
EOF
|
|
|
|
cat > "$PERSONALITIES_DIR/orchestrator/config.yaml" << 'EOF'
|
|
name: orchestrator
|
|
description: Coordinates other agents, breaks down tasks
|
|
model: claude-sonnet-4-20250514
|
|
max_turns: 50
|
|
lifecycle: long-running
|
|
EOF
|
|
|
|
echo "Created: $PERSONALITIES_DIR/orchestrator/"
|
|
}
|
|
|
|
install_deps
|
|
setup_dirs
|
|
|
|
STORAGE=$(detect_storage)
|
|
echo "Storage backend: $STORAGE"
|
|
|
|
case "$STORAGE" in
|
|
sqlite) init_sqlite ;;
|
|
duckdb) init_duckdb ;;
|
|
postgres) echo "PostgreSQL - tables managed by postgres skill" ;;
|
|
esac
|
|
|
|
# Save storage type for run.sh
|
|
echo "$STORAGE" > "$AGENTS_DATA_DIR/.storage"
|
|
|
|
configure_caddy
|
|
create_example_personality
|
|
|
|
echo "Agents setup complete"
|