{"slug": "veta-ai-agent-that-qa-tests-android-apps", "title": "Veta: AI agent that QA-tests Android apps", "summary": "Veta, an AI agent that QA-tests Android apps using a swarm of autonomous sub-agents, runs 100% of its AI inference on AMD GPUs via Fireworks AI or self-hosted vLLM on ROCm. The system replaces scripted UI tests with AI-driven visual, functional, and accessibility testing, scaling from 10 to 100 concurrent sessions on Kubernetes.", "body_md": "*Autonomous AI agent swarm for visual, functional, and accessibility testing of Android apps and mobile web — 100% of AI inference runs on AMD GPUs (Fireworks AI on AMD Instinct / self-hosted vLLM on ROCm), with containerized Android instances running locally.*\n\n[Overview](#overview) • [Features](#features) • [Architecture](#architecture) • [How it works](#how-it-works) • [API](#api) • [Getting started](#getting-started) • [Project structure](#project-structure) • [Tech stack](#tech-stack)\n\nBuilt for theNo benchmarks, no constraints, just build: give an AI model eyes and hands, and let it QA your Android apps.[AMD Developer Hackathon ACT II]— Unicorn Track.\n\nVeta replaces brittle, scripted UI tests with an **AI-driven QA agent that watches an Android screen**, decides what to do next based on a plain-English task description, and executes actions via ADB. Each run produces a pass/fail verdict, a complete action trace, and video/log artifacts — the same output a human QA tester would produce, at machine speed.\n\nSessions run in parallel across a fleet of containerized Android instances (redroid), managed by a scheduler with a warm pool and autoscaling. A web dashboard lets humans launch sessions, watch live screen mirrors, and review results.\n\n| Input type | Description |\n|---|---|\nAPK |\nUpload an Android APK, install it on a clean Android instance, and run a task against the native app |\nWeb domain |\nProvide a URL to test inside a sandboxed mobile browser, with optional login credentials |\nContext file |\nAttach `.txt` , `.md` , `.docx` , or `.pdf` checklist alongside the task — contents are folded into the agent's working prompt at runtime |\n\nThe system starts at **~10 concurrent sessions** on a single host and scales to **~100 concurrent sessions** on Kubernetes.\n\n**Every single model call — planning, execution, verification, reporting — runs on AMD GPUs.** Zero inference happens on non-AMD hardware by default.\n\n| Path | What runs on AMD | Hardware |\n|---|---|---|\nFireworks AI (default) |\nPlanner, executor, verifier, reporter | AMD Instinct MI250/MI300X |\nSelf-hosted vLLM + ROCm |\nSame pipeline, your hardware | Any AMD GPU via ROCm |\n\nThe agent has no fallback to non-AMD inference providers. Gemini, OpenRouter, and Anthropic are listed as optional alternatives in the settings UI — none are enabled or used by default. Out of the box, **100% of AI compute is AMD.**\n\n**Sub-agent architecture**— Planner creates a checklist before execution. Executor drives per-step decisions. Verifier reviews the verdict before finalizing. Reporter writes a structured post-run analysis. Each is independently promptable and swappable.**Fixed action vocabulary**—`tap`\n\n,`long_press`\n\n,`swipe`\n\n,`scroll`\n\n,`drag`\n\n,`type`\n\n,`type_multi`\n\n,`key`\n\n,`back`\n\n,`dismiss_keyboard`\n\n,`wait`\n\n,`assert`\n\n,`done`\n\n,`request_manual_control`\n\n,`note`\n\n. The model never emits raw shell commands.**Ground-truth screen tracking**— Per-step`screen_changed`\n\nflag from hierarchy hash comparison, plus Android activity name monitoring via`dumpsys`\n\n. The model knows \"which screen am I on\" independently of visual appearance.**Toast interception**— Post-action polling of the accessibility hierarchy catches system Toasts (~2-3.5s window) with code-level certainty, not visual guesswork.**Loop detection**— Tracks repeated identical actions with no`screen_changed`\n\neffect; auto-inserts`back`\n\nafter 3 repeats to break stuck states.**Verification gate**— Before accepting a`done`\n\nverdict, a second model pass (verifier) checks every planned checkpoint against the action history. Can send the session back for more exploration if evidence is thin.**Post-run analysis**— Reporter sub-agent generates a structured write-up: executive summary, checkpoint breakdown, technical explanation, severity rating, remediation recommendations. Available via API and PDF/CSV export.**Containerized Android fleet**— Redroid containers with per-container binder device slots, health checks, warm pool management, and clean-state teardown between sessions.**Real-time streaming**— WebSocket for log entries, step records, status changes, and live device screen mirror during a running session. Degrades to polling fallback if WebSocket fails.**Step replay player**— Focus view and filmstrip view with touch marker animation, screenshot browsing, and auto-play.** Export**— PDF report (jsPDF with professional layout, verdict, metadata, checkpoint breakdown, steps table, logs table) and CSV log export.**Session controls**— End (stop + cancel) and restart running sessions from the UI.** Device identity profiles**— Pixel 7 Pro, Pixel 6, Samsung S24, and more — spoofed via ro.build properties for realistic testing.** 100% AMD-powered AI**— Fireworks AI on AMD Instinct (default) or self-hosted vLLM on AMD ROCm. Every`call_model_json()`\n\nin the agent pipeline hits AMD GPUs.\n\n``` php\n                      +------------------+\n      People / CI --> |  New Session     |  APK / URL + task description\n                      |  Input Form      |--------------------------------+\n                      +------------------+                                |\n                                                                          v\n                      +------------------+                      +-------------------+\n                      |  Fleet Dashboard |  <--------------->   |  Session          |\n                      |  (live overview) |                      |  Scheduler        |\n                      +------------------+                      +--------+----------+\n                                                                          |\n                      +-----------------------------------------------------+------------------------------------------+\n                      v                          v                          v                                          v\n               redroid container           redroid container           redroid container                    ... up to ~100\n               + agent sidecar             + agent sidecar             + agent sidecar\n               (observe->decide->act)      (observe->decide->act)      (observe->decide->act)\n                      |                          |                          |\n                      +---------> Object storage (screenshots, step JPEGs, logs)\n                      +---------> Results DB (Postgres — sessions, steps, log entries, analyses, devices, settings, users)\n```\n\n| Component | Responsibility |\n|---|---|\nNew Session form |\nAccept APK upload or domain URL, task description, device/browser profile, optional context file |\nFleet Dashboard |\nLive overview of every session with status bar, search, filter, sort, pagination |\nSession Detail |\nLive screen mirror + structured log stream + replay player + AI analysis panel |\nSession Scheduler |\nDispatch loop (2s tick) + fleet loop (10s tick): queued sessions -> reserve/boot device -> dispatch agent |\nAndroid container (redroid) |\nOne isolated Android 11 instance per session via Docker, with per-container binder device slots |\nAgent sidecar |\nObserve -> decide -> act loop. Sub-agents: planner, executor, verifier, reporter |\nDevice Manager |\nContainer lifecycle: provision, deploy, health-check, teardown, warm pool maintenance |\nPostgres DB |\nSource of truth for session metadata, steps, log entries, device state, session analyses, settings, users |\nFile storage |\nPer-step replay screenshots (downscaled JPEG), uploaded APKs, stored on local filesystem |\n\nEach session runs a single sidecar process that cycles through five steps:\n\n**Observe**— Capture a screenshot (`adb screencap`\n\nvia adbutils) and the UI element hierarchy (`uiautomator dump`\n\nparsed into a flat element list with bounds, text, content-desc, and class).**Decide**— Send image + hierarchy + task description + action history to the AI model. The model returns one structured action from the fixed vocabulary.**Act**— Translate the action into ADB calls:`input tap`\n\n,`input swipe`\n\n,`input text`\n\n,`input keyevent`\n\n, etc.**Settle**— Poll for system Toasts in the ~1s post-action window, then capture a fresh screenshot for the next step.** Ground truth check**— Per-step hierarchy hash detects whether the screen actually changed; activity name tracking detects navigation independently of visual appearance.\n\nThe model must explicitly emit `assert`\n\n(expected vs. actual comparison) and `done`\n\n(pass/fail verdict with reasoning) — it cannot wander indefinitely.\n\n```\nTask + screenshot\n    |\n    v\n+------------------+\n|  Planner         |  Creates 3-6 concrete checkpoints from task + screenshot (+ APK manifest activities)\n|  (once)          |  Degrades gracefully to empty list -> executor/verifier fall back to free-form task\n+--------+---------+\n         | plan checklist\n         v\n+------------------+\n|  Executor        |  Per-step: screenshot + hierarchy + history -> one action\n|  (per step)      |  Retries on bad generation (3 attempts). Loop detection. Activity tracking.\n+--------+---------+\n         | \"done\" with proposed verdict\n         v\n+------------------+\n|  Verifier        |  Checkpoint-by-checkpoint review against action history + final screenshot\n|  (once)          |  Can set should_continue=true -> executor keeps going. Falls back to executor's verdict.\n+--------+---------+\n         | final verdict\n         v\n+------------------+\n|  Reporter        |  Post-verdict write-up: summary, breakdown, technical explanation, severity, recommendations\n|  (once)          |  Persisted to DB. Serves Analysis tab + PDF export. Degrades to checkpoint-derived fallback.\n+------------------+\n```\n\n- User submits an APK (or URL), task description, and optional context file through the New Session form.\n- API creates a\n`queued`\n\nsession row with sequential ID (e.g.`S9403`\n\n). - Session Scheduler's dispatch loop (every 2s) picks up queued sessions up to the parallelism limit.\n- Scheduler reserves an idle device or cold-provisions one (binds a port + binder slot, boots redroid container, waits for adb +\n`sys.boot_completed`\n\n). - Session transitions\n`booting`\n\n->`initializing`\n\n->`running`\n\n. The agent sidecar installs the APK (if applicable), runs the planner, then begins the observe-decide-act loop. - When the executor emits\n`done`\n\n, the verifier reviews the evidence. If it passes, the session transitions to`analyzing`\n\n(device is released immediately), the reporter generates the write-up, then the session settles into`passed`\n\nor`failed`\n\n. - Artifacts (step screenshots, action log, analysis) are persisted. The container is torn down. The fleet loop (every 10s) re-deploys the device for the warm pool.\n- The Fleet Dashboard and Session Detail reflect the final verdict and analysis in real time.\n\n| Status | Meaning |\n|---|---|\n`queued` |\nWaiting for an available device slot |\n`booting` |\nAndroid container is starting up |\n`initializing` |\nInstalling APK / preparing agent |\n`running` |\nAgent loop is actively executing the task |\n`awaiting_questions` |\nReview mode: waiting for user answers to clarifying questions |\n`awaiting_approval` |\nReview mode: waiting for user to approve the generated test plan |\n`analyzing` |\nVerdict reached; reporter generating write-up |\n`passed` |\nTask completed successfully |\n`failed` |\nTask completed but assertions failed |\n`stopped` |\nManually stopped by a user |\n`error` |\nInfrastructure or system error |\n`timed_out` |\nAgent exceeded max steps (50) |\n\n- Each redroid container runs Android 11 (1080x2400, 480dpi) with nav bar + soft keyboard disabled via\n`policy_control`\n\nand`pm disable-user`\n\n. - Devices are identified by\n`D-{hex}`\n\nID, assigned a host port (5555-5655 range) and a**binder slot**(binder/hwbinder/vndbinder triplet) for the kernel's binder driver — a hard cap set at`modprobe`\n\ntime on the host. - Warm pool: idle, healthy devices maintained up to a user-configurable target. Devices in\n`error`\n\nstate are reaped after 30s backoff. - Health checks run every 10s: container running +\n`sys.boot_completed`\n\n. - Device identity profiles (Pixel 7 Pro / Pixel 6 / Samsung S24) are applied via\n`ro.build`\n\nproperty overrides before any app touches the device.\n\nThe backend is a Python FastAPI server at `/api`\n\n. Interactive docs at `http://localhost:8000/docs`\n\n.\n\n| Method | Path | Purpose |\n|---|---|---|\n`POST` |\n`/api/sessions` |\nCreate a new session (multipart form: APK file or URL + task + device profile) |\n`GET` |\n`/api/sessions` |\nList sessions (cursor-paginated, filterable by status/device/build/text search) |\n`GET` |\n`/api/sessions/stats` |\nDashboard stats (running/queued/passed/failed counts + success rate) |\n`GET` |\n`/api/sessions/{id}` |\nGet single session details |\n`PATCH` |\n`/api/sessions/{id}/control` |\nControl session (action: `end` or `restart` ) |\n`POST` |\n`/api/sessions/{id}/answers` |\nSubmit answers to review clarifying questions |\n`POST` |\n`/api/sessions/{id}/approve` |\nApprove review-mode test plan and queue session |\n`POST` |\n`/api/sessions/{id}/regenerate-plan` |\nRegenerate test plan from existing answers |\n`POST` |\n`/api/sessions/{id}/back-to-questions` |\nGo back to clarifying questions from plan review |\n`GET` |\n`/api/sessions/{id}/logs` |\nGet log entries with cursor (`since` ) |\n`POST` |\n`/api/sessions/{id}/logs` |\nCreate a log entry |\n`GET` |\n`/api/sessions/{id}/steps` |\nGet replay steps with cursor (`since_step` ) |\n`GET` |\n`/api/sessions/{id}/steps/{n}/screenshot` |\nGet step screenshot (JPEG) |\n`GET` |\n`/api/sessions/{id}/analysis` |\nGet session analysis write-up |\n`POST` |\n`/api/sessions/{id}/analysis/regenerate` |\nRegenerate analysis for a finished session |\n`WS` |\n`/api/sessions/{id}/events` |\nWebSocket — real-time log/step/status deltas |\n`WS` |\n`/api/sessions/{id}/stream` |\nWebSocket — live screen frame stream (PNG) |\n\n| Method | Path | Purpose |\n|---|---|---|\n`GET` |\n`/api/devices` |\nList all devices |\n`POST` |\n`/api/devices` |\nProvision a new device (boots redroid container) |\n`GET` |\n`/api/devices/capacity` |\nBinder slot usage (total/used/available) |\n`POST` |\n`/api/devices/{id}/start` |\nStart an offline device |\n`POST` |\n`/api/devices/{id}/stop` |\nStop a running device |\n`POST` |\n`/api/devices/{id}/restart` |\nRestart a device (re-deploy container) |\n`POST` |\n`/api/devices/{id}/maintenance` |\nToggle maintenance mode |\n`POST` |\n`/api/devices/{id}/warm` |\nAdjust warm instance count (delta -8 to +8) |\n`DELETE` |\n`/api/devices/{id}` |\nRemove device (tear down container, free port/slot) |\n\n| Method | Path | Purpose |\n|---|---|---|\n`POST` |\n`/api/auth/login` |\nLogin (email + password) |\n`POST` |\n`/api/auth/signup` |\nRegister new user |\n`POST` |\n`/api/auth/logout` |\nLogout |\n\n| Method | Path | Purpose |\n|---|---|---|\n`GET` |\n`/api/settings` |\nGet app settings (workspace, region, notifications, parallelism, API key, warm pool size, max devices) |\n`PUT` |\n`/api/settings` |\nUpdate app settings |\n\n- Docker Engine and Docker Compose (for Postgres and redroid containers)\n- Python 3.11+\n- Node.js 20+\n- An AI provider API key (Fireworks AI on AMD Instinct recommended, or any OpenAI-compatible provider)\n\n**Development** (hot reload):\n\n```\n./dev.sh\n```\n\n**Production** (built frontend, no reload):\n\n```\n./start.sh\n```\n\nBoth scripts start Postgres (if not running), run migrations, and launch the full stack. `Ctrl-C`\n\nstops everything.\n\n```\ncd backend\ncp .env.example .env\n```\n\nEdit `.env`\n\nto set your `AI_API_KEY`\n\nand any other settings.\n\n```\ndocker compose up -d\n```\n\nOr manually:\n\n```\ndocker run -d --name veta-pg \\\n  -e POSTGRES_USER=postgres \\\n  -e POSTGRES_PASSWORD=postgres \\\n  -e POSTGRES_DB=veta \\\n  -p 5432:5432 \\\n  postgres:16-alpine\ncd backend\npip install -e .\nalembic upgrade head\nuvicorn app.main:app --reload --host 0.0.0.0 --port 8000\n```\n\nThe API starts at `http://localhost:8000`\n\n. Docs at `http://localhost:8000/docs`\n\n.\n\nOn first boot, the server auto-seeds admin user (\n\n`admin`\n\n/`admin`\n\n) and default settings.\n\n```\ncd frontend\nnpm install\nnpm run dev\n```\n\nThe dashboard starts at `http://localhost:8080`\n\n. Login with any email/password.\n\nSet\n\n`VITE_API_URL`\n\nto change the backend address (default`http://localhost:8000`\n\n).\n\n```\n# Load binder kernel module (adjust device count for your host)\nsudo modprobe binder_linux devices=\"binder,hwbinder,vndbinder\"\n\n# Example for 3 concurrent devices:\n# devices=\"binder,hwbinder,vndbinder,binder1,hwbinder1,vndbinder1,binder2,hwbinder2,vndbinder2\"\n\n# Ensure adb is installed and accessible\nadb devices\n\n# Set required env vars\nexport REDROID_IMAGE=redroid/redroid:11.0.0-latest\n```\n\n| Variable | Default | Description |\n|---|---|---|\n`DATABASE_URL` |\n`postgresql+asyncpg://postgres:postgres@localhost:5432/veta` |\nPostgres connection string |\n`REDROID_IMAGE` |\n`redroid/redroid:11.0.0-latest` |\nAndroid container image |\n`ADB_HOST` |\n`localhost` |\nADB host address |\n`REDROID_PORT_START` |\n`5555` |\nStart of port range for device ADB |\n`REDROID_PORT_END` |\n`5655` |\nEnd of port range (up to ~100 devices) |\n`BINDER_SLOTS` |\nauto-detected from `/dev` |\nOverride for binder slot count |\n`AI_API_KEY` |\n-- | AI provider API key (also configurable via Settings UI) |\n`AI_PROVIDER` |\n`fireworks` |\nAI provider: `fireworks` , `veta-ai` , `google-gemini` , `openrouter` , `deepseek` , `anthropic` |\n`AI_MODEL` |\nprovider default | Model name override |\n`MODEL_ENDPOINT` |\nprovider default | API base URL override |\n\n```\nveta/\n  Docs/                        Design documents, wireframes, logo\n  server/                      vLLM inference server (AMD ROCm)\n    veta_inference_server.ipynb  Notebook: serve vision models on AMD GPUs via vLLM\n    bin/                         cloudflared binary for tunnel\n\n  backend/                     FastAPI backend API\n    app/\n      main.py                  FastAPI entrypoint + lifespan (auto-seed, stale cleanup, dispatch + fleet loops)\n      config.py                pydantic-settings (.env / env vars)\n      database.py              Async SQLAlchemy engine + session factory\n      dispatcher.py            Session dispatch loop + fleet health loop\n      device_manager.py        Redroid container lifecycle, port/binder allocation, warm pool, health checks\n      device_events.py         SSE device state change notifications\n      apk_utils.py             APK metadata extraction (aapt + apkutils)\n      screenshot_store.py      Per-step screenshot downscale + JPEG storage\n      models/                  SQLAlchemy ORM models (session, step, log_entry, device, settings, session_analysis, user)\n      schemas/                 Pydantic request/response schemas (camelCase JSON)\n      routers/                 REST + WebSocket endpoint handlers (sessions, steps, logs, devices, auth, settings, stream)\n      services/\n        session_analysis.py    Build + store session analysis (bridges reporter sub-agent to DB)\n    adapters/                  Port implementations (ApkInspectorImpl, etc.)\n    alembic/                   Database migrations\n    scripts/\n      seed.py                  Seed admin user + default settings\n    uploads/                   Uploaded APKs + step screenshot storage\n\n  agent/                       AI agent sidecar\n    agents/\n      base.py                  Shared retry logic (generate_with_retries)\n      planner.py               Pre-execution checkpoint builder\n      executor.py              Per-step action decision\n      verifier.py              Post-decision verification\n      reporter.py              Post-verdict write-up\n    core/\n      adb.py                   adbutils device handle\n      device.py                Screenshots, action execution, marker extraction, activity tracking\n      hierarchy.py             XML hierarchy parsing, element signature hashing\n      model_client.py          Multi-provider AI client (Gemini SDK + OpenAI-compat) with retry + JSON extraction\n      apk.py                   APK metadata extraction, install/launch on device\n      cancellation.py          Thread-safe session cancellation\n      thinking_hooks.py        Real-time thinking indicator callbacks\n      modes.py                 Mode configs (review/run) + allowed action groups\n      skill_text.py            Loads agent playbook into system prompt\n    ports/                     Protocol interfaces for dependency injection\n      apk_inspector.py         ApkInspector protocol (get_all_activities, get_apk_details)\n    skills/                    Agent playbook (loaded into system context)\n      SKILL.md                 Master playbook — decision loop, confidence/targeting rules, verdict discipline\n      actions.md               Full action vocabulary with semantics for each action type\n      elements.md              UI element taxonomy — how to recognize and interact with different UI components\n      scenarios.md             Step-by-step playbooks for authentication, permissions, onboarding, forms, search\n      debugging.md             Recovery strategies for stuck states, loop detection, unexpected screens\n    memory.py                  SessionMemory — action history, loop detection, activity tracking, screen stack\n    orchestrator.py            Session state machine wiring all sub-agents together (booting -> ... -> passed/failed)\n    phases.py                  Phase-based lifecycle (SetupPhase, ReviewPhase, RunPhase)\n    runner.py                  Compatibility entrypoint (delegates to orchestrator)\n\n  frontend/                    TanStack Start web dashboard\n    src/\n      routes/                  File-based routing\n        __root.tsx             Root layout + sidebar + auth\n        index.tsx              Fleet Dashboard (stat bar, search, filter, sort, pagination, session cards)\n        session.$id.tsx        Session Detail (live mirror, log stream, replay player, analysis panel, export, filmstrip)\n        new-session.tsx        New Session form (APK/URL toggle, file drag-drop, context attachment, device profile)\n        devices.tsx            Device Farm (card grid, provision dialog, warm pool controls, binder tracking)\n        history.tsx            Run History (table view, sort, filter)\n        settings.tsx           Settings (workspace, execution, API key, notifications, integrations)\n        login.tsx / signup.tsx Auth pages\n      components/\n        session-card.tsx       Fleet dashboard session card\n        session-analysis-panel.tsx  Analysis tab UI\n        ui/                    shadcn/ui primitives (50+ components)\n      lib/\n        api.ts                 API client (fetch + WebSocket wrappers, all endpoints)\n        auth.ts                Session storage auth\n        session-report.ts      PDF + CSV export (jsPDF with professional layout)\n    public/                    Static assets (favicon, logo)\n```\n\nLocated in `agent/agents/`\n\n. Each is independently promptable and can be retried or swapped without affecting the others.\n\n| Agent | File | Purpose |\n|---|---|---|\nplanner |\n`planner.py` |\nBuilds 3-6 concrete checkpoints from task + first screenshot (+ APK manifest). Runs once before execution. |\nexecutor |\n`executor.py` |\nPer-step decision: screenshot + hierarchy + history -> one action. Retries on bad generation (3 attempts). |\nverifier |\n`verifier.py` |\nCheckpoint-by-checkpoint review against action history. Can send session back for more exploration. |\nreporter |\n`reporter.py` |\nPost-verdict structured write-up. Falls back to checkpoint-derived summary on model failure. |\n\nLocated in `agent/core/`\n\n.\n\n| Module | Purpose |\n|---|---|\n`device` |\nScreenshots, action execution dispatch, activity tracking, marker extraction |\n`hierarchy` |\nUiAutomator hierarchy dump + parsing + element signature hashing |\n`model_client` |\nMulti-provider HTTP client (Gemini SDK + OpenAI-compat, Fireworks on AMD Instinct), JSON extraction, retry logic |\n`apk` |\nAPK install, package discovery, app launch on device |\n`adb` |\nShared adbutils device handle |\n`cancellation` |\nThread-safe session cancellation registry |\n`modes` |\nMode configs (review/run) + action group definitions |\n`skill_text` |\nAgent playbook loaded into the executor's system prompt |\n\n| Provider | SDK | Backend hardware | Models | Status |\n|---|---|---|---|---|\nFireworks AI |\n`openai` |\nAMD Instinct MI250/MI300X |\n`qwen3.7-plus` , `firefunction-v2` , Gemma 4 |\n✅ Default (100% AMD) |\nVeta AI (self-hosted) |\n`openai` |\nAMD ROCm (vLLM) |\nAny HF vision model (Qwen2.5-VL, Gemma, Llama) | ✅ 100% AMD |\nGoogle Gemini |\n`google-genai` |\nGoogle TPU | `gemma-4-26b-a4b-it` |\n⬜ Optional |\nOpenRouter |\n`openai` |\nVaries | `openai/gpt-4o-mini` , any routed model |\n⬜ Optional |\nDeepseek |\n`openai` |\nVaries | `deepseek-v4-flash` |\n⬜ Optional |\nAnthropic |\n`openai` |\nVaries | Anthropic models via OpenAI-compat endpoint | ⬜ Optional |\n\n100% of inference runs on AMD out of the box.The two AMD-backed providers (Fireworks + self-hosted ROCm) handle every agent call. Gemini, OpenRouter, Deepseek, and Anthropic are optional alternatives — none are enabled by default.\n\nThe agent playbook (`agent/skills/`\n\n) is loaded into the executor's system context:\n\n| File | Purpose |\n|---|---|\n`SKILL.md` |\nMaster playbook — decision loop, confidence/targeting rules, verdict discipline |\n`actions.md` |\nFull action vocabulary with semantics for each action type |\n`elements.md` |\nUI element taxonomy — recognizing and interacting with buttons, sliders, toggles, dropdowns, dialogs |\n`scenarios.md` |\nStep-by-step playbooks for authentication, permissions, onboarding, forms, search |\n`debugging.md` |\nRecovery strategies for stuck states, loop detection, unexpected screens |\n\n| Layer | Technology |\n|---|---|\nBackend |\nPython 3.11+, FastAPI, SQLAlchemy (async), Alembic, PostgreSQL |\nAgent loop |\nPython, httpx, Pillow, google-genai SDK, openai SDK |\nFrontend |\nReact 19, TanStack Start, TanStack Router, Tailwind CSS v4, shadcn/ui |\nAI inference (cloud, default) |\nFireworks AI — AMD Instinct MI250/MI300X (100% AMD) |\nAI inference (self-hosted) |\nvLLM + AMD ROCm (100% AMD) |\nAndroid runtime |\nDocker, redroid (Android 11), ADB, adbutils, uiautomator |\nInfrastructure |\nDocker, Docker Compose (dev), Kubernetes (target) |\nReal-time |\nWebSocket (live frame stream + events bus), SSE fallback |\nExport |\njsPDF + jspdf-autotable (PDF), CSV |\n\n| Approach | Cost per session (~50 steps) | When to use |\n|---|---|---|\nFireworks API (AMD Instinct) |\n~$0.02-0.05 | Development, low-volume QA |\nSelf-hosted vLLM on ROCm |\nGPU electricity only | Production, high-volume CI/CD |\nGemini CachedContent |\n~$0.01 (95% cached) | Optional fallback / multi-provider |", "url": "https://wpnews.pro/news/veta-ai-agent-that-qa-tests-android-apps", "canonical_source": "https://github.com/Vip3r-MC/Veta", "published_at": "2026-07-16 14:03:48+00:00", "updated_at": "2026-07-16 14:25:35.660425+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-agents", "ai-infrastructure", "ai-products", "ai-tools"], "entities": ["Veta", "AMD", "Fireworks AI", "ROCm", "vLLM", "Kubernetes", "Android", "ADB"], "alternates": {"html": "https://wpnews.pro/news/veta-ai-agent-that-qa-tests-android-apps", "markdown": "https://wpnews.pro/news/veta-ai-agent-that-qa-tests-android-apps.md", "text": "https://wpnews.pro/news/veta-ai-agent-that-qa-tests-android-apps.txt", "jsonld": "https://wpnews.pro/news/veta-ai-agent-that-qa-tests-android-apps.jsonld"}}