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
151 lines
5.4 KiB
Python
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()
|