diff --git a/playground/artemis_container/.dockerignore b/playground/artemis_container/.dockerignore new file mode 100644 index 0000000..e8f9bd9 --- /dev/null +++ b/playground/artemis_container/.dockerignore @@ -0,0 +1,15 @@ +.git +.gitignore +.env +__pycache__/ +*.pyc +*.pyo +*.pyd +.pytest_cache/ +.coverage +htmlcov/ +node_modules/ +dist/ +build/ +*.egg-info/ +playground/ diff --git a/playground/artemis_container/Dockerfile b/playground/artemis_container/Dockerfile new file mode 100644 index 0000000..f057f4c --- /dev/null +++ b/playground/artemis_container/Dockerfile @@ -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"] diff --git a/playground/artemis_container/README.md b/playground/artemis_container/README.md new file mode 100644 index 0000000..93a5f31 --- /dev/null +++ b/playground/artemis_container/README.md @@ -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-` 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 + ``` diff --git a/playground/artemis_container/docker-compose.yml b/playground/artemis_container/docker-compose.yml new file mode 100644 index 0000000..1580025 --- /dev/null +++ b/playground/artemis_container/docker-compose.yml @@ -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 diff --git a/playground/artemis_container/docker-entrypoint.sh b/playground/artemis_container/docker-entrypoint.sh new file mode 100644 index 0000000..7971f8a --- /dev/null +++ b/playground/artemis_container/docker-entrypoint.sh @@ -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 "$@"