Skip to content

feat: add streaming toggle to chat assistant interface #22

feat: add streaming toggle to chat assistant interface

feat: add streaming toggle to chat assistant interface #22

name: Deploy Chat Agent
on:
push:
branches:
- main
paths:
- 'apps/agent/**'
- '.github/workflows/deploy-chat-agent.yml'
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: wildeditor-chat-agent
jobs:
# Build and push Docker image
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/luminarimud/wildeditor-chat-agent
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: apps/agent/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Deploy to production
deploy:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment:
name: production
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: Add server to known hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -H ${{ secrets.PRODUCTION_HOST }} >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts
- name: Deploy Chat Agent to Production
env:
# Map existing secrets to chat agent env vars
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
AI_PROVIDER: ${{ secrets.AI_PROVIDER }}
OPENAI_MODEL: ${{ secrets.OPENAI_MODEL }}
DEEPSEEK_MODEL: ${{ secrets.DEEPSEEK_MODEL }}
MCP_API_KEY: ${{ secrets.WILDEDITOR_MCP_KEY }}
run: |
# Create deployment script (following MCP pattern)
cat > deploy-agent.sh << 'EOF'
#!/bin/bash
set -e
echo "🚀 Starting Chat Agent deployment..."
# Configuration
DOCKER_IMAGE="ghcr.io/luminarimud/wildeditor-chat-agent:latest"
CONTAINER_NAME="wildeditor-chat-agent"
# Check Docker access
if groups | grep -q docker; then
DOCKER_CMD="docker"
echo "✅ User is in docker group"
elif sudo -n true 2>/dev/null; then
DOCKER_CMD="sudo docker"
echo "✅ Passwordless sudo available"
else
echo "❌ Error: User needs to be in docker group or have passwordless sudo access"
exit 1
fi
# Create agent directory
echo "📁 Setting up agent directory..."
mkdir -p ~/wildeditor-chat-agent
cd ~/wildeditor-chat-agent
echo "✅ Working directory: $(pwd)"
# Login to GitHub Container Registry
echo "GITHUB_TOKEN_PLACEHOLDER" | $DOCKER_CMD login ghcr.io -u GITHUB_ACTOR_PLACEHOLDER --password-stdin
# Pull latest image
echo "📦 Pulling latest Chat Agent Docker image..."
$DOCKER_CMD pull $DOCKER_IMAGE
# Stop existing container
echo "🛑 Stopping existing container..."
$DOCKER_CMD stop $CONTAINER_NAME || true
$DOCKER_CMD rm $CONTAINER_NAME || true
# Debug: Check which environment variables are available
echo "🔍 Checking environment variables..."
echo "AI_PROVIDER=${AI_PROVIDER:-not set}"
if [ -n "$OPENAI_API_KEY" ]; then
echo "OPENAI_API_KEY=[SET] (length: ${#OPENAI_API_KEY})"
else
echo "OPENAI_API_KEY=[NOT SET]"
fi
if [ -n "$DEEPSEEK_API_KEY" ]; then
echo "DEEPSEEK_API_KEY=[SET] (length: ${#DEEPSEEK_API_KEY})"
else
echo "DEEPSEEK_API_KEY=[NOT SET]"
fi
echo "MCP_API_KEY=${MCP_API_KEY:+[SET]}"
# Start new container with host networking (same as MCP and backend)
echo "🏃 Starting new Chat Agent container..."
# Build docker run command with environment variables
DOCKER_RUN_CMD="$DOCKER_CMD run -d --name $CONTAINER_NAME --restart unless-stopped --network host"
# Add environment variables only if they are set
[ -n "$AI_PROVIDER" ] && DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e MODEL_PROVIDER='$AI_PROVIDER'"
[ -n "$OPENAI_API_KEY" ] && DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e OPENAI_API_KEY='$OPENAI_API_KEY'"
[ -n "$DEEPSEEK_API_KEY" ] && DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e DEEPSEEK_API_KEY='$DEEPSEEK_API_KEY'"
[ -n "$OPENAI_MODEL" ] && DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e MODEL_NAME='$OPENAI_MODEL'"
[ -n "$DEEPSEEK_MODEL" ] && DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e DEEPSEEK_MODEL='$DEEPSEEK_MODEL'"
[ -n "$MCP_API_KEY" ] && DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e MCP_API_KEY='$MCP_API_KEY'"
# Backend API key removed - using MCP as single contact surface
# Add static environment variables
DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e WILDERNESS_MCP_URL='http://localhost:8001'"
# Backend accessed only through MCP now
DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e FRONTEND_URL='https://wildedit.luminarimud.com'"
DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e HOST='0.0.0.0'"
DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e PORT='8002'"
DOCKER_RUN_CMD="$DOCKER_RUN_CMD -e LOG_LEVEL='INFO'"
# Add volume and image
DOCKER_RUN_CMD="$DOCKER_RUN_CMD -v $HOME/logs/wildeditor-chat-agent:/var/log/chat-agent"
DOCKER_RUN_CMD="$DOCKER_RUN_CMD $DOCKER_IMAGE"
# Execute the docker run command
echo "Executing: $DOCKER_RUN_CMD" | sed 's/OPENAI_API_KEY=[^ ]*/OPENAI_API_KEY=[HIDDEN]/g' | sed 's/DEEPSEEK_API_KEY=[^ ]*/DEEPSEEK_API_KEY=[HIDDEN]/g'
eval $DOCKER_RUN_CMD
# Wait for container to be healthy
echo "🏥 Waiting for health check..."
for i in {1..30}; do
if ! $DOCKER_CMD ps | grep -q $CONTAINER_NAME; then
echo "❌ Container is not running"
$DOCKER_CMD logs --tail 10 $CONTAINER_NAME
exit 1
fi
if curl -s --connect-timeout 5 --max-time 10 http://localhost:8002/health/ >/dev/null 2>&1; then
echo "✅ Chat Agent container is healthy!"
break
fi
if [ $i -eq 30 ]; then
echo "❌ Container failed to become healthy after 60 seconds"
echo "🔍 Container status:"
$DOCKER_CMD ps -a | grep $CONTAINER_NAME || true
echo "🔍 Full container logs:"
$DOCKER_CMD logs $CONTAINER_NAME 2>&1 || true
echo "🔍 Container inspect (environment variables):"
$DOCKER_CMD inspect $CONTAINER_NAME | grep -A 20 '"Env"' || true
exit 1
fi
echo "Waiting... ($i/30)"
sleep 2
done
# Test endpoints
echo "🧪 Testing Chat Agent endpoints..."
if curl -s --connect-timeout 5 --max-time 10 http://localhost:8002/health/ >/dev/null; then
echo "✅ Health endpoint working"
else
echo "❌ Health endpoint failed"
exit 1
fi
# Cleanup old images
echo "🧹 Cleaning up old images..."
$DOCKER_CMD image prune -f
echo "🎉 Chat Agent deployment completed successfully!"
EOF
# Replace placeholders
sed -i "s/GITHUB_TOKEN_PLACEHOLDER/${{ secrets.GITHUB_TOKEN }}/g" deploy-agent.sh
sed -i "s/GITHUB_ACTOR_PLACEHOLDER/${{ github.actor }}/g" deploy-agent.sh
# Copy deployment script to server
echo "📋 Copying deployment script to server..."
scp -o StrictHostKeyChecking=no deploy-agent.sh ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }}:/tmp/
# Execute deployment on server with environment variables
echo "🚀 Executing deployment on server..."
ssh -o StrictHostKeyChecking=no ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }} "
chmod +x /tmp/deploy-agent.sh
export AI_PROVIDER='${AI_PROVIDER:-openai}'
export OPENAI_API_KEY='$OPENAI_API_KEY'
export DEEPSEEK_API_KEY='$DEEPSEEK_API_KEY'
export OPENAI_MODEL='${OPENAI_MODEL:-gpt-4-turbo}'
export DEEPSEEK_MODEL='${DEEPSEEK_MODEL:-deepseek-chat}'
export MCP_API_KEY='$MCP_API_KEY'
# Backend API key not needed - MCP is single contact surface
/tmp/deploy-agent.sh
"
- name: Verify deployment
run: |
sleep 10
echo "🔍 Verifying Chat Agent deployment..."
# Test from server
ssh -o StrictHostKeyChecking=no ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }} "
echo '🏥 Testing Chat Agent health endpoint from server:'
if curl -s --connect-timeout 5 --max-time 10 http://localhost:8002/health/; then
echo ''
echo '✅ Chat Agent health check PASSED'
exit 0
else
echo ''
echo '❌ Chat Agent health check FAILED'
echo 'Container logs:'
docker logs --tail 10 wildeditor-chat-agent || true
exit 1
fi
"
echo "✅ Chat Agent deployment verified successfully!"