Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions playground/artemis_container/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.git
.gitignore
.env
__pycache__/
*.pyc
*.pyo
*.pyd
.pytest_cache/
.coverage
htmlcov/
node_modules/
dist/
build/
*.egg-info/
playground/
59 changes: 59 additions & 0 deletions playground/artemis_container/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM python:3.12-slim

WORKDIR /app

# Install system dependencies, Android toolchain (adb), OpenCV runtime, FFmpeg, and curl
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
curl \
git \
adb \
ffmpeg \
libgl1 \
libglib2.0-0 \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# Copy core Artemis package structure and configuration from repository root
COPY artemis/ /app/artemis/
COPY apps/ /app/apps/
COPY mcp_server/ /app/mcp_server/
COPY config/ /app/config/
COPY pyproject.toml setup.py README.md LICENSE /app/

# Install dependencies and artemis in editable mode
RUN pip install --no-cache-dir -e /app

# Copy custom container entrypoint script
COPY playground/artemis_container/docker-entrypoint.sh /app/docker-entrypoint.sh
RUN chmod +x /app/docker-entrypoint.sh

# Environment Configuration
ENV PYTHONUNBUFFERED=1
ENV PYTHONPATH=/app
ENV ARTEMIS_APP_DIR=/app
ENV PORT=8080

# Expose internal Artemis Admin Console and Stream port
EXPOSE 8080

# Health check to ensure Artemis Admin Console is alive
HEALTHCHECK --interval=15s --timeout=3s --start-period=10s --retries=3 \
CMD curl -f http://localhost:8080/api/system/health || curl -f http://localhost:8080/ || exit 1

ENTRYPOINT ["/app/docker-entrypoint.sh"]
CMD ["uvicorn", "apps.admin_console.server:app", "--host", "0.0.0.0", "--port", "8080"]
92 changes: 92 additions & 0 deletions playground/artemis_container/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# 🤖 Artemis Session Container

Dedicated, session-isolated container image for running the Artemis Autonomous AI Agent on Google Cloud **Container-Optimized OS (COS)**.

---

## 📌 Architecture & Lifecycle

When a user initiates a session via the [Backend Manager](../backend_manager/README.md), the backend dynamically spawns an instance of this container named `artemis-session-<session_id>` on the shared `artemis-net` bridge network.

---

## 🔑 Key Features

1. **Automated ADB Bridging**:
- The container entrypoint automatically connects to the target Cuttlefish instance with automatic retry handling.

2. **Multimodal Perception & Toolchain**:
- Packaged with Android Platform Tools, ffmpeg, OpenCV libraries, and Python.

3. **Real-time Event Streaming**:
- Hosts the Artemis Admin Console server exposing SSE and WebSocket endpoints for live streaming agent reasoning, thought steps, and action execution directly to the frontend.

4. **Dynamic Selector & Coordinate Fallback Engine**:
- Drives real-time automated navigation on the connected Cuttlefish emulator using Artemis's multimodal reasoning pipeline.

---

## 📁 Directory Structure

```
playground/artemis_container/
├── Dockerfile # Python 3.12 slim with adb, ffmpeg, OpenCV, and Artemis
├── docker-entrypoint.sh # Automated ADB connection loop & service startup
├── docker-compose.yml # Compose spec for testing standalone session
├── .dockerignore
└── README.md # Documentation & operational guide
```

---

## 🚀 Building & Running

### 1. Build the Artemis Container Image
From the repository root:
```bash
docker build -f playground/artemis_container/Dockerfile -t artemis:latest .
```

### 2. Run Standalone with Docker CLI
```bash
# Ensure bridge network exists
docker network create artemis-net || true

# Run Artemis session container targeting Cuttlefish on port 6520
docker run -d \
--name artemis-session-sample \
--network artemis-net \
--add-host host.docker.internal:host-gateway \
-e SESSION_ID=sample-123 \
-e ADB_DEVICE_SERIAL=host.docker.internal:6520 \
-e GEMINI_API_KEY="your-gemini-key" \
-p 8080:8080 \
artemis:latest
```

### 3. Run with Docker Compose (Test Setup)
```bash
cd playground/artemis_container
docker-compose up -d
```

---

## 🧪 Verification & Health Check

1. **Verify ADB Connection inside Container**:
```bash
docker exec -it artemis-session-sample adb devices
```

2. **Verify Server Health Probe**:
```bash
curl http://localhost:8080/api/system/health
# Returns: {"status": "ok", ...}
```

3. **Verify Trace Streaming**:
```bash
curl -N http://localhost:8080/stream/events
# Real-time Server-Sent Events stream
```
48 changes: 48 additions & 0 deletions playground/artemis_container/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

version: '3.8'

services:
artemis-session:
build:
context: ../..
dockerfile: playground/artemis_container/Dockerfile
container_name: artemis-session-sample
restart: unless-stopped
ports:
- "8080:8080"
environment:
- SESSION_ID=sample-session-123
- ADB_DEVICE_SERIAL=host.docker.internal:6520
- PORT=8080
- PYTHONUNBUFFERED=1
# Model & Perception API Keys (pass from host environment)
- GEMINI_API_KEY=${GEMINI_API_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY}
networks:
- artemis-net
extra_hosts:
# Allows reaching Cuttlefish emulator running on the COS VM host network
- "host.docker.internal:host-gateway"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/system/health"]
interval: 15s
timeout: 3s
retries: 3

networks:
artemis-net:
name: artemis-net
driver: bridge
73 changes: 73 additions & 0 deletions playground/artemis_container/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/bin/bash
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -e

echo "=================================================="
echo " ARTEMIS SESSION CONTAINER INITIALIZATION"
echo " Session ID : ${SESSION_ID:-standalone-dev}"
echo " ADB Target : ${ADB_DEVICE_SERIAL:-not-configured}"
echo "=================================================="

# Start ADB daemon inside container
adb start-server

# If ADB target is specified, attempt connection with retry loop
if [ -n "$ADB_DEVICE_SERIAL" ]; then
# Resolve host gateway IP if targeting host.docker.internal on Linux bridge
TARGET_SERIAL="$ADB_DEVICE_SERIAL"
if [[ "$ADB_DEVICE_SERIAL" == host.docker.internal:* ]]; then
PORT_PART="${ADB_DEVICE_SERIAL#host.docker.internal:}"
DEFAULT_GW=$(ip route show default 2>/dev/null | awk '{print $3}' | head -n1)
if [ -n "$DEFAULT_GW" ]; then
echo "[Artemis Entrypoint] Detected bridge gateway IP: ${DEFAULT_GW} for host.docker.internal"
TARGET_SERIAL="${DEFAULT_GW}:${PORT_PART}"
fi
fi

echo "[Artemis Entrypoint] Connecting to target Android device at ${TARGET_SERIAL}..."

MAX_RETRIES=15
RETRY_COUNT=0
CONNECTED=false

while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
echo "[Artemis Entrypoint] Attempting adb connect ${TARGET_SERIAL} (Attempt $((RETRY_COUNT + 1))/${MAX_RETRIES})..."
CONNECT_OUTPUT=$(adb connect "${TARGET_SERIAL}" 2>&1 || true)
echo " -> ${CONNECT_OUTPUT}"

# Check if connected
if echo "${CONNECT_OUTPUT}" | grep -q "connected to"; then
CONNECTED=true
break
fi

RETRY_COUNT=$((RETRY_COUNT + 1))
sleep 2
done

if [ "$CONNECTED" = true ]; then
echo "[Artemis Entrypoint] ADB successfully connected to ${TARGET_SERIAL}."
else
echo "[Artemis Entrypoint] Warning: Could not establish immediate ADB connection to ${TARGET_SERIAL}. Container will continue; agent will reconnect on demand."
fi
fi

# List currently attached devices
echo "[Artemis Entrypoint] Active ADB Devices:"
adb devices -l

echo "[Artemis Entrypoint] Starting Artemis Admin Console & Agent Server on port ${PORT:-8080}..."
exec "$@"