feat: add streaming toggle to chat assistant interface #22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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!" |