Files
Artemis-Eapil/artemis/interfaces/cli/commands/init.py
T
somew1nd 206a9ce921 feat: initial release of ARTEMIS Android Agent & Automation Platform
ARTEMIS is an autonomous multimodal Android agent and mobile UI automation
platform engineered for physical devices and emulators. It combines state-of-the-art
multimodal Vision-Language Models (VLMs) with hierarchical closed-loop planning,
resilient self-healing, and deep Android subsystem integration.

Key Features & Architectural Highlights:
- Dual-Engine Orchestration:
  * Pro Engine: Multi-agent closed-loop (Planner -> Operator -> Validator/Failure Analyzer -> Summarizer) powered by LangGraph.
  * Flash Engine: Ultra-fast reactive loop for deterministic, low-latency UI execution (<35 steps).
- Multimodal Perception & Grounding:
  * Hybrid visual screenshot grounding, real-time OCR extraction, and XML accessibility hierarchy parsing.
  * Dynamic-First, Coordinate-Fallback locating strategy for maximum resilience against UI drift.
- Autonomous Self-Healing & Diagnostics:
  * Failure analyzer and safety net for popup dismissal, crash recovery, and auto-retry.
  * Diagnostic sub-agents for log analysis, video recording inspection, and object detection.
- Unified CLI & Python SDK:
  * Rich CLI with commands: init, doctor, run, trace, batch, bench, server, and mcp.
  * Fluent Python SDK with Pydantic structured output models and package locking.
- Multi-Provider LLM Architecture:
  * Support for Google Gemini, OpenAI, Anthropic Claude, Vertex AI, OpenRouter, xAI Grok, and local endpoints (Ollama/vLLM).
  * Centralized configuration in config/artemis.jsonc.
- Native MCP & Observability:
  * Model Context Protocol (MCP) server endpoints for AI IDEs.
  * Full trace recording with before/after screenshots, action overlays, and execution replays.

Change-Id: I430b93ee2b76b54cc5a3c6eeccd15d2cf29830a1
2026-08-13 11:46:47 -07:00

151 lines
5.4 KiB
Python

# 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.
"""Interactive setup wizard for first-time ARTEMIS onboarding (artemis init)."""
import shutil
import subprocess
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt
from artemis.config import ROOT_DIR
def init_command() -> None:
"""Interactive quickstart wizard to configure API keys and connect your device."""
console = Console()
console.print()
console.print(
Panel(
"[bold cyan]β˜• Welcome to Artemis Mobile Testing Framework[/bold cyan]\n"
"[dim]Let's get you set up in 10 seconds![/dim]",
expand=False,
)
)
# 1. Select Provider
console.print("\n[bold]Step 1: Choose Primary LLM Provider[/bold]")
console.print(" [1] Google Gemini (Recommended - Default)")
console.print(" [2] OpenAI (GPT-4o)")
console.print(" [3] Anthropic (Claude 3.5 Sonnet)")
console.print(" [4] OpenRouter")
choice = Prompt.ask("Select provider", choices=["1", "2", "3", "4"], default="1")
provider_map = {
"1": ("GEMINI_API_KEY", "Google Gemini"),
"2": ("OPENAI_API_KEY", "OpenAI"),
"3": ("ANTHROPIC_API_KEY", "Anthropic"),
"4": ("OPEN_ROUTER_API_KEY", "OpenRouter"),
}
env_key, provider_name = provider_map[choice]
# 2. Enter API Key
console.print(f"\n[bold]Step 2: Enter your {provider_name} API Key[/bold]")
api_key = Prompt.ask(f"Enter {env_key}", password=True)
while not api_key.strip():
console.print("[bold red]API Key cannot be empty.[/bold red]")
api_key = Prompt.ask(f"Enter {env_key}", password=True)
# 3. Scan for Android Devices
console.print("\n[bold]Step 3: Detecting Android Devices / Emulators...[/bold]")
detected_devices = []
adb_path = shutil.which("adb")
if adb_path:
try:
res = subprocess.run(
[adb_path, "devices", "-l"],
capture_output=True,
text=True,
timeout=5,
)
lines = [line_str.strip() for line_str in res.stdout.splitlines() if line_str.strip()]
for line in lines[1:]:
parts = line.split()
if len(parts) >= 2 and parts[1] == "device":
serial = parts[0]
extra = " ".join(parts[2:])
detected_devices.append((serial, extra))
except Exception:
pass
selected_serial = ""
if detected_devices:
console.print(
f"[bold green]βœ” Found {len(detected_devices)} connected device(s):[/bold green]"
)
for idx, (serial, extra) in enumerate(detected_devices, 1):
console.print(f" [{idx}] {serial} ({extra})")
if len(detected_devices) == 1:
selected_serial = detected_devices[0][0]
console.print(f"[dim]Auto-selected device: {selected_serial}[/dim]")
else:
dev_choice = Prompt.ask(
"Select device index",
choices=[str(i) for i in range(1, len(detected_devices) + 1)],
default="1",
)
selected_serial = detected_devices[int(dev_choice) - 1][0]
else:
console.print(
"[bold yellow]⚠ No connected device detected right now.[/bold yellow]\n"
"[dim]Artemis will auto-detect your device when you connect it later.[/dim]"
)
# 4. Generate .env File
env_content = [
"# ==============================================================================",
"# β˜• ARTEMIS Environment Configuration (Generated by 'artemis init')",
"# ==============================================================================",
f"{env_key}={api_key.strip()}",
"",
"# Android Device Configuration",
"ADB_HOST=127.0.0.1",
"ADB_PORT=5037",
]
if selected_serial:
env_content.append(f"ADB_DEVICE_SERIAL={selected_serial}")
else:
env_content.append("# ADB_DEVICE_SERIAL=emulator-5554")
env_content.extend(
[
"",
"# Execution Defaults",
"ARTEMIS_DEFAULT_PROFILE=pro",
"ARTEMIS_DEFAULT_MODEL=gemini-2.5-flash",
"ARTEMIS_TRACES_DIR=./traces",
"",
]
)
env_path = ROOT_DIR / ".env"
env_path.write_text("\n".join(env_content), encoding="utf-8")
console.print()
console.print(
Panel(
f"[bold green]πŸŽ‰ Setup completed successfully![/bold green]\n\n"
f"Configured [bold cyan]{provider_name}[/bold cyan] in [dim]{env_path}[/dim]\n\n"
"Try running your first task:\n"
' [bold cyan]artemis run "Open YouTube and search for Lo-Fi Hip Hop"[/bold cyan]\n\n'
"Or run health diagnostics anytime with:\n"
" [bold cyan]artemis doctor[/bold cyan]",
title="β˜• Ready to Go!",
expand=False,
)
)
console.print()