You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
7.5 KiB
205 lines
7.5 KiB
#!/bin/bash |
|
############################################################################### |
|
# OpenClaw Agent Onboarding Script |
|
# |
|
# Fully automated: creates workspace, registers in agents.yaml + |
|
# project_registry.yaml, installs systemd service, reloads monitor. |
|
# |
|
# Usage: |
|
# ./onboard.sh <agent_id> <agent_name> <project_id> [qdrant_host] |
|
# |
|
# Examples: |
|
# ./onboard.sh crypto "CryptoBot" crypto # local agent |
|
# ./onboard.sh remote1 "RemoteBot" advert 100.115.94.1 # remote agent |
|
############################################################################### |
|
|
|
set -e |
|
|
|
WORKSPACE="/root/.openclaw/workspace" |
|
TEMPLATE_DIR="$WORKSPACE/templates" |
|
AGENTS_YAML="$WORKSPACE/agents.yaml" |
|
REGISTRY="$WORKSPACE/skills/mem0-integration/project_registry.yaml" |
|
|
|
RED='\033[0;31m' |
|
GREEN='\033[0;32m' |
|
YELLOW='\033[1;33m' |
|
BLUE='\033[0;34m' |
|
NC='\033[0m' |
|
|
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } |
|
log_success() { echo -e "${GREEN}[OK]${NC} $1"; } |
|
log_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; } |
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; } |
|
|
|
setup_user_env() { |
|
export XDG_RUNTIME_DIR=/run/user/$(id -u) |
|
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus" |
|
} |
|
|
|
if [ $# -lt 3 ]; then |
|
echo "Usage: $0 <agent_id> <agent_name> <project_id> [qdrant_host]" |
|
echo "" |
|
echo " agent_id Unique identifier (lowercase, no spaces)" |
|
echo " agent_name Display name for the agent" |
|
echo " project_id Project to register in (must exist in project_registry.yaml)" |
|
echo " qdrant_host Optional: Qdrant host for remote agents (default: localhost)" |
|
exit 1 |
|
fi |
|
|
|
AGENT_ID="$1" |
|
AGENT_NAME="$2" |
|
PROJECT_ID="$3" |
|
QDRANT_HOST="${4:-localhost}" |
|
USER_ID="wang_yuanzhang" |
|
DATE=$(date +%Y-%m-%d) |
|
|
|
AGENT_WORKSPACE="$WORKSPACE/agents/${AGENT_ID}-workspace" |
|
AGENT_CONFIG_DIR="/root/.openclaw-${AGENT_ID}" |
|
SYSTEMD_UNIT="openclaw-gateway-${AGENT_ID}.service" |
|
|
|
log_info "Onboarding agent: ${AGENT_NAME} (${AGENT_ID})" |
|
log_info "Project: ${PROJECT_ID}, Qdrant: ${QDRANT_HOST}" |
|
|
|
# Pre-check: ensure agent doesn't already exist |
|
if python3 "$WORKSPACE/scripts/parse_agents.py" info "$AGENT_ID" >/dev/null 2>&1; then |
|
log_error "Agent '${AGENT_ID}' already exists in agents.yaml" |
|
exit 1 |
|
fi |
|
|
|
# 1. Create workspace from templates |
|
if [ -d "$AGENT_WORKSPACE" ]; then |
|
log_error "Workspace already exists: $AGENT_WORKSPACE" |
|
exit 1 |
|
fi |
|
|
|
log_info "Creating workspace at $AGENT_WORKSPACE..." |
|
mkdir -p "$AGENT_WORKSPACE/skills/mem0-integration" |
|
mkdir -p "$AGENT_WORKSPACE/memory" |
|
|
|
for tmpl in IDENTITY.md.template SOUL.md.template; do |
|
base="${tmpl%.template}" |
|
sed -e "s/{{AGENT_ID}}/${AGENT_ID}/g" \ |
|
-e "s/{{AGENT_NAME}}/${AGENT_NAME}/g" \ |
|
-e "s/{{AGENT_ROLE}}/TODO: define role/g" \ |
|
-e "s/{{PROJECT_ID}}/${PROJECT_ID}/g" \ |
|
-e "s/{{DATE}}/${DATE}/g" \ |
|
"$TEMPLATE_DIR/agent-workspace/$tmpl" > "$AGENT_WORKSPACE/$base" |
|
done |
|
|
|
ln -sf "$WORKSPACE/USER.md" "$AGENT_WORKSPACE/USER.md" |
|
ln -sf "$WORKSPACE/AGENTS.md" "$AGENT_WORKSPACE/AGENTS.md" |
|
|
|
sed -e "s/{{AGENT_ID}}/${AGENT_ID}/g" \ |
|
-e "s/{{AGENT_NAME}}/${AGENT_NAME}/g" \ |
|
-e "s/{{QDRANT_HOST}}/${QDRANT_HOST}/g" \ |
|
-e "s/{{USER_ID}}/${USER_ID}/g" \ |
|
"$TEMPLATE_DIR/agent-workspace/skills/mem0-integration/config.yaml.template" \ |
|
> "$AGENT_WORKSPACE/skills/mem0-integration/config.yaml" |
|
|
|
log_success "Workspace created" |
|
|
|
# 2. Register in agents.yaml (uses sys.argv to avoid shell injection) |
|
if [ "$QDRANT_HOST" = "localhost" ]; then |
|
AGENT_TYPE="local-systemd" |
|
python3 - "$AGENTS_YAML" "$AGENT_ID" "$AGENT_NAME" "$AGENT_TYPE" \ |
|
"$AGENT_CONFIG_DIR" "$AGENT_WORKSPACE" "$SYSTEMD_UNIT" "$PROJECT_ID" <<'PYEOF' |
|
import sys, yaml |
|
yaml_path, aid, aname, atype, profile, ws, unit, proj = sys.argv[1:9] |
|
with open(yaml_path, 'r', encoding='utf-8') as f: |
|
data = yaml.safe_load(f) |
|
data['agents'][aid] = { |
|
'name': aname, 'type': atype, |
|
'profile_dir': profile, 'workspace': ws, |
|
'service': {'unit': unit}, |
|
'env_file': f'{aid}-gateway.env', |
|
'projects': [proj], |
|
} |
|
with open(yaml_path, 'w', encoding='utf-8') as f: |
|
yaml.dump(data, f, default_flow_style=False, allow_unicode=True, sort_keys=False) |
|
PYEOF |
|
else |
|
AGENT_TYPE="remote-http" |
|
python3 - "$AGENTS_YAML" "$AGENT_ID" "$AGENT_NAME" "$AGENT_TYPE" \ |
|
"$AGENT_WORKSPACE" "$QDRANT_HOST" "$PROJECT_ID" <<'PYEOF' |
|
import sys, yaml |
|
yaml_path, aid, aname, atype, ws, qhost, proj = sys.argv[1:8] |
|
with open(yaml_path, 'r', encoding='utf-8') as f: |
|
data = yaml.safe_load(f) |
|
data['agents'][aid] = { |
|
'name': aname, 'type': atype, |
|
'workspace': ws, |
|
'service': {'health_url': f'http://{qhost}:18789/health', 'timeout': 5000}, |
|
'projects': [proj], |
|
'qdrant_host': qhost, |
|
} |
|
with open(yaml_path, 'w', encoding='utf-8') as f: |
|
yaml.dump(data, f, default_flow_style=False, allow_unicode=True, sort_keys=False) |
|
PYEOF |
|
fi |
|
log_success "Registered in agents.yaml (type: ${AGENT_TYPE})" |
|
|
|
# 3. Register in project_registry.yaml |
|
if grep -q "\"${AGENT_ID}\"" "$REGISTRY" 2>/dev/null; then |
|
log_warning "Agent ${AGENT_ID} already in project registry" |
|
else |
|
if grep -q "^ ${PROJECT_ID}:" "$REGISTRY"; then |
|
sed -i "/^ ${PROJECT_ID}:/,/owner:/ { |
|
/members:/a\\ - \"${AGENT_ID}\" |
|
}" "$REGISTRY" |
|
log_success "Registered ${AGENT_ID} in project ${PROJECT_ID}" |
|
else |
|
log_warning "Project ${PROJECT_ID} not found in registry. Add manually." |
|
fi |
|
fi |
|
|
|
# 4. Generate systemd service + env files (local agents only) |
|
if [ "$AGENT_TYPE" = "local-systemd" ]; then |
|
SERVICE_FILE="$WORKSPACE/systemd/${SYSTEMD_UNIT}" |
|
sed -e "s/{{AGENT_ID}}/${AGENT_ID}/g" \ |
|
-e "s/{{AGENT_NAME}}/${AGENT_NAME}/g" \ |
|
"$TEMPLATE_DIR/systemd/agent-gateway.service.template" > "$SERVICE_FILE" |
|
log_success "Service file: $SERVICE_FILE" |
|
|
|
ENV_FILE="$WORKSPACE/systemd/${AGENT_ID}-gateway.env" |
|
sed -e "s/{{AGENT_ID}}/${AGENT_ID}/g" \ |
|
-e "s/{{AGENT_NAME}}/${AGENT_NAME}/g" \ |
|
-e "s/{{QDRANT_HOST}}/${QDRANT_HOST}/g" \ |
|
"$TEMPLATE_DIR/systemd/agent-gateway.env.template" > "$ENV_FILE" |
|
chmod 600 "$ENV_FILE" |
|
log_success "Env file: $ENV_FILE" |
|
|
|
# 5. Install and start the service |
|
setup_user_env |
|
mkdir -p ~/.config/systemd/user/ |
|
cp "$SERVICE_FILE" "$HOME/.config/systemd/user/${SYSTEMD_UNIT}" |
|
systemctl --user daemon-reload |
|
systemctl --user enable "${SYSTEMD_UNIT}" |
|
log_success "Service installed and enabled" |
|
|
|
# 6. Create OpenClaw profile directory |
|
mkdir -p "$AGENT_CONFIG_DIR" |
|
log_info "Profile directory created: $AGENT_CONFIG_DIR" |
|
log_warning "You must create $AGENT_CONFIG_DIR/openclaw.json before starting" |
|
fi |
|
|
|
# 7. Reload the monitor to pick up the new agent |
|
systemctl restart openclaw-agent-monitor 2>/dev/null && log_success "Monitor reloaded" || log_warning "Monitor reload failed (may not be running)" |
|
|
|
echo "" |
|
log_success "Onboarding complete for ${AGENT_NAME} (${AGENT_ID})" |
|
echo "" |
|
|
|
if [ "$AGENT_TYPE" = "local-systemd" ]; then |
|
log_info "Remaining steps:" |
|
echo " 1. Edit agent identity: vim $AGENT_WORKSPACE/IDENTITY.md" |
|
echo " 2. Create openclaw.json: vim $AGENT_CONFIG_DIR/openclaw.json" |
|
echo " (copy from /root/.openclaw/openclaw.json and modify)" |
|
echo " 3. Start: systemctl --user start ${SYSTEMD_UNIT}" |
|
echo "" |
|
elif [ "$AGENT_TYPE" = "remote-http" ]; then |
|
log_info "Remaining steps:" |
|
echo " 1. Deploy the agent on the remote server at ${QDRANT_HOST}" |
|
echo " 2. Ensure Tailscale connectivity to ${QDRANT_HOST}:6333 (Qdrant)" |
|
echo " 3. Configure the remote agent to use Qdrant collection: mem0_v4_shared" |
|
echo "" |
|
fi
|
|
|