android-midscene-automation 0.2.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -1
- package/README.md +63 -1
- package/artemis-main/.dockerignore +15 -0
- package/artemis-main/.env.example +34 -0
- package/artemis-main/CONTRIBUTING.md +35 -0
- package/artemis-main/Dockerfile +68 -0
- package/artemis-main/LICENSE +202 -0
- package/artemis-main/Makefile +115 -0
- package/artemis-main/README.md +322 -0
- package/artemis-main/README_CN.md +320 -0
- package/artemis-main/apps/__init__.py +15 -0
- package/artemis-main/apps/admin_console/__init__.py +19 -0
- package/artemis-main/apps/admin_console/core/__init__.py +13 -0
- package/artemis-main/apps/admin_console/core/config.py +43 -0
- package/artemis-main/apps/admin_console/core/security.py +178 -0
- package/artemis-main/apps/admin_console/core/state.py +243 -0
- package/artemis-main/apps/admin_console/database/__init__.py +13 -0
- package/artemis-main/apps/admin_console/database/connection.py +60 -0
- package/artemis-main/apps/admin_console/database/repositories/__init__.py +13 -0
- package/artemis-main/apps/admin_console/database/repositories/session_repository.py +564 -0
- package/artemis-main/apps/admin_console/database/repositories/step_repository.py +512 -0
- package/artemis-main/apps/admin_console/database/repositories/trace_repository.py +133 -0
- package/artemis-main/apps/admin_console/index.html +3787 -0
- package/artemis-main/apps/admin_console/replay_manager.py +2585 -0
- package/artemis-main/apps/admin_console/routers/__init__.py +13 -0
- package/artemis-main/apps/admin_console/routers/media.py +198 -0
- package/artemis-main/apps/admin_console/routers/replay.py +91 -0
- package/artemis-main/apps/admin_console/routers/sessions.py +239 -0
- package/artemis-main/apps/admin_console/routers/steps.py +109 -0
- package/artemis-main/apps/admin_console/routers/stream.py +56 -0
- package/artemis-main/apps/admin_console/routers/system.py +761 -0
- package/artemis-main/apps/admin_console/routers/tasks.py +517 -0
- package/artemis-main/apps/admin_console/schemas/__init__.py +13 -0
- package/artemis-main/apps/admin_console/schemas/task_schema.py +47 -0
- package/artemis-main/apps/admin_console/server.py +508 -0
- package/artemis-main/apps/admin_console/services/__init__.py +13 -0
- package/artemis-main/apps/admin_console/services/device_stream_service.py +137 -0
- package/artemis-main/apps/admin_console/services/ipc_service.py +262 -0
- package/artemis-main/apps/admin_console/services/media_service.py +623 -0
- package/artemis-main/apps/admin_console/services/model_service.py +148 -0
- package/artemis-main/apps/admin_console/services/task_preset_catalog.py +514 -0
- package/artemis-main/apps/admin_console/services/task_queue_service.py +1719 -0
- package/artemis-main/apps/admin_console/services/worker_process_io.py +144 -0
- package/artemis-main/apps/showcase_ui/README.md +31 -0
- package/artemis-main/apps/showcase_ui/angular.json +132 -0
- package/artemis-main/apps/showcase_ui/package-lock.json +9472 -0
- package/artemis-main/apps/showcase_ui/package.json +39 -0
- package/artemis-main/apps/showcase_ui/proxy.conf.json +23 -0
- package/artemis-main/apps/showcase_ui/public/favicon.ico +0 -0
- package/artemis-main/apps/showcase_ui/public/logo.png +0 -0
- package/artemis-main/apps/showcase_ui/public/logo.svg +56 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.html +24 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.scss +49 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.spec.ts +42 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.ts +32 -0
- package/artemis-main/apps/showcase_ui/src/app/app.config.ts +29 -0
- package/artemis-main/apps/showcase_ui/src/app/app.routes.ts +27 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream-startup.spec.ts +108 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html +1436 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.scss +3973 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.ts +2235 -0
- package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.html +380 -0
- package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.scss +1171 -0
- package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.ts +270 -0
- package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.html +433 -0
- package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.scss +987 -0
- package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.ts +632 -0
- package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.html +130 -0
- package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.scss +406 -0
- package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.ts +74 -0
- package/artemis-main/apps/showcase_ui/src/app/components/nav-switcher/nav-switcher.component.scss +115 -0
- package/artemis-main/apps/showcase_ui/src/app/components/nav-switcher/nav-switcher.component.ts +52 -0
- package/artemis-main/apps/showcase_ui/src/app/core/data/smart-tasks.data.ts +334 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/language.service.spec.ts +55 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/language.service.ts +61 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/translate.pipe.ts +11 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/zh-cn.ts +651 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/markdown.model.ts +43 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/pro-tuning.model.spec.ts +47 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/pro-tuning.model.ts +165 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/session.model.ts +85 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/stream.model.ts +246 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/system.model.ts +118 -0
- package/artemis-main/apps/showcase_ui/src/app/core/services/task-recommendation.service.ts +111 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.html +2130 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.scss +5204 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.ts +1189 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.html +39 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.scss +151 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.ts +58 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.html +201 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.scss +886 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.ts +324 -0
- package/artemis-main/apps/showcase_ui/src/app/services/agent.service.spec.ts +418 -0
- package/artemis-main/apps/showcase_ui/src/app/services/agent.service.ts +2012 -0
- package/artemis-main/apps/showcase_ui/src/app/services/system.service.spec.ts +173 -0
- package/artemis-main/apps/showcase_ui/src/app/services/system.service.ts +620 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/action-formatter.util.spec.ts +513 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/action-formatter.util.ts +1015 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/image-overlay.util.spec.ts +85 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/image-overlay.util.ts +662 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/markdown-parser.util.spec.ts +70 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/markdown-parser.util.ts +383 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/recording-timeline.util.spec.ts +107 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/recording-timeline.util.ts +123 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/run-info.util.spec.ts +92 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/run-info.util.ts +116 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/stream-aggregator.util.spec.ts +640 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/stream-aggregator.util.ts +1021 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/tool-formatter.util.spec.ts +375 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/tool-formatter.util.ts +1419 -0
- package/artemis-main/apps/showcase_ui/src/index.html +37 -0
- package/artemis-main/apps/showcase_ui/src/main.ts +22 -0
- package/artemis-main/apps/showcase_ui/src/styles.scss +60 -0
- package/artemis-main/apps/showcase_ui/tsconfig.app.json +23 -0
- package/artemis-main/apps/showcase_ui/tsconfig.json +27 -0
- package/artemis-main/apps/showcase_ui/tsconfig.spec.json +23 -0
- package/artemis-main/artemis/__init__.py +44 -0
- package/artemis-main/artemis/__main__.py +18 -0
- package/artemis-main/artemis/_legacy_imports.py +94 -0
- package/artemis-main/artemis/_version.py +30 -0
- package/artemis-main/artemis/agents/__init__.py +17 -0
- package/artemis-main/artemis/agents/checker/checker.json +9 -0
- package/artemis-main/artemis/agents/checker/checker.py +859 -0
- package/artemis-main/artemis/agents/diagnoser/diagnoser.json +23 -0
- package/artemis-main/artemis/agents/diagnoser/diagnoser.py +608 -0
- package/artemis-main/artemis/agents/explorer/constants.py +52 -0
- package/artemis-main/artemis/agents/explorer/explorer.json +57 -0
- package/artemis-main/artemis/agents/explorer/explorer.py +473 -0
- package/artemis-main/artemis/agents/explorer/geometry.py +73 -0
- package/artemis-main/artemis/agents/explorer/native_runner.py +878 -0
- package/artemis-main/artemis/agents/explorer/perception_tools.py +632 -0
- package/artemis-main/artemis/agents/explorer/run_setup.py +403 -0
- package/artemis-main/artemis/agents/explorer/screen_index.py +266 -0
- package/artemis-main/artemis/agents/explorer/tiers.py +110 -0
- package/artemis-main/artemis/agents/explorer/tool_declarations.py +394 -0
- package/artemis-main/artemis/agents/explorer/universal_runner.py +317 -0
- package/artemis-main/artemis/agents/flash/context_compressor.py +452 -0
- package/artemis-main/artemis/agents/flash/flash_runner.md +51 -0
- package/artemis-main/artemis/agents/flash/flash_summarizer.md +53 -0
- package/artemis-main/artemis/agents/flash/flash_summarizer_single.md +54 -0
- package/artemis-main/artemis/agents/flash/runner.py +1167 -0
- package/artemis-main/artemis/agents/flash/summarizer.py +511 -0
- package/artemis-main/artemis/agents/history_analyzer/history_analyzer.md +8 -0
- package/artemis-main/artemis/agents/history_analyzer/history_analyzer.py +182 -0
- package/artemis-main/artemis/agents/image_processor/image_processor.md +74 -0
- package/artemis-main/artemis/agents/image_processor/image_processor.py +322 -0
- package/artemis-main/artemis/agents/log_analyzer/log_analyzer.md +15 -0
- package/artemis-main/artemis/agents/log_analyzer/log_analyzer.py +403 -0
- package/artemis-main/artemis/agents/log_analyzer/log_reader_sub_agent.md +8 -0
- package/artemis-main/artemis/agents/log_analyzer/output_analyzer.md +11 -0
- package/artemis-main/artemis/agents/log_analyzer/output_analyzer.py +163 -0
- package/artemis-main/artemis/agents/object_detector/object_detector.json +9 -0
- package/artemis-main/artemis/agents/object_detector/object_detector.py +211 -0
- package/artemis-main/artemis/agents/operator/operator.json +3 -0
- package/artemis-main/artemis/agents/operator/operator.py +1394 -0
- package/artemis-main/artemis/agents/operator/prompts.py +1064 -0
- package/artemis-main/artemis/agents/outputter/outputter.md +36 -0
- package/artemis-main/artemis/agents/outputter/outputter.py +552 -0
- package/artemis-main/artemis/agents/planner/planner.json +32 -0
- package/artemis-main/artemis/agents/planner/planner.py +436 -0
- package/artemis-main/artemis/agents/prompt_assembly.py +79 -0
- package/artemis-main/artemis/agents/summarizer/summarizer.py +190 -0
- package/artemis-main/artemis/agents/validator/action_execution.py +98 -0
- package/artemis-main/artemis/agents/validator/categories.py +33 -0
- package/artemis-main/artemis/agents/validator/execution_loop.py +488 -0
- package/artemis-main/artemis/agents/validator/incidents.py +120 -0
- package/artemis-main/artemis/agents/validator/pixel_safety_net.md +15 -0
- package/artemis-main/artemis/agents/validator/precondition_pixel.py +320 -0
- package/artemis-main/artemis/agents/validator/precondition_xml.py +672 -0
- package/artemis-main/artemis/agents/validator/tool_declarations.py +332 -0
- package/artemis-main/artemis/agents/validator/validator.py +188 -0
- package/artemis-main/artemis/agents/video_analyzer/__init__.py +15 -0
- package/artemis-main/artemis/agents/video_analyzer/audio_native.py +543 -0
- package/artemis-main/artemis/agents/video_analyzer/blackboard.py +821 -0
- package/artemis-main/artemis/agents/video_analyzer/chunk_agentic.py +455 -0
- package/artemis-main/artemis/agents/video_analyzer/chunk_conversation.py +491 -0
- package/artemis-main/artemis/agents/video_analyzer/chunk_native.py +437 -0
- package/artemis-main/artemis/agents/video_analyzer/conflict_resolution.py +137 -0
- package/artemis-main/artemis/agents/video_analyzer/gemini_files.py +162 -0
- package/artemis-main/artemis/agents/video_analyzer/native_coordinator.py +541 -0
- package/artemis-main/artemis/agents/video_analyzer/reliability.py +128 -0
- package/artemis-main/artemis/agents/video_analyzer/universal_engine.py +487 -0
- package/artemis-main/artemis/agents/video_analyzer/universal_tools.py +323 -0
- package/artemis-main/artemis/agents/video_analyzer/video_analyzer.md +51 -0
- package/artemis-main/artemis/agents/video_analyzer/video_analyzer.py +875 -0
- package/artemis-main/artemis/agents/video_analyzer/video_sub_agent.md +15 -0
- package/artemis-main/artemis/agents/video_analyzer/video_sub_agent_audio.md +12 -0
- package/artemis-main/artemis/clients/accessibility_client.py +438 -0
- package/artemis-main/artemis/clients/screen_client_factory.py +403 -0
- package/artemis-main/artemis/config/__init__.py +309 -0
- package/artemis-main/artemis/config/agent.py +1098 -0
- package/artemis-main/artemis/config/constants.py +151 -0
- package/artemis-main/artemis/config/core/__init__.py +24 -0
- package/artemis-main/artemis/config/core/engine.py +118 -0
- package/artemis-main/artemis/config/core/interpolator.py +78 -0
- package/artemis-main/artemis/config/llm.py +267 -0
- package/artemis-main/artemis/config/paths.py +244 -0
- package/artemis-main/artemis/config/runtime.py +197 -0
- package/artemis-main/artemis/config/settings.py +315 -0
- package/artemis-main/artemis/constants.py +47 -0
- package/artemis-main/artemis/context.py +289 -0
- package/artemis-main/artemis/controllers/__init__.py +41 -0
- package/artemis-main/artemis/controllers/controller_factory.py +41 -0
- package/artemis-main/artemis/controllers/device_controller.py +29 -0
- package/artemis-main/artemis/controllers/types.py +37 -0
- package/artemis-main/artemis/controllers/unified_controller.py +649 -0
- package/artemis-main/artemis/core/__init__.py +21 -0
- package/artemis-main/artemis/core/diagnostics/__init__.py +90 -0
- package/artemis-main/artemis/core/diagnostics/adb_keys.py +270 -0
- package/artemis-main/artemis/core/diagnostics/adb_server_connection.py +330 -0
- package/artemis-main/artemis/core/diagnostics/device_smoke.py +364 -0
- package/artemis-main/artemis/core/diagnostics/emulator_manager.py +501 -0
- package/artemis-main/artemis/core/diagnostics/engine.py +438 -0
- package/artemis-main/artemis/core/diagnostics/hierarchy_parity.py +216 -0
- package/artemis-main/artemis/core/diagnostics/probes/adb_probe.py +887 -0
- package/artemis-main/artemis/core/diagnostics/probes/base.py +45 -0
- package/artemis-main/artemis/core/diagnostics/probes/credentials_probe.py +296 -0
- package/artemis-main/artemis/core/diagnostics/probes/host_probe.py +427 -0
- package/artemis-main/artemis/core/diagnostics/probes/runtime_probe.py +169 -0
- package/artemis-main/artemis/core/diagnostics/probes/toolchain_probe.py +139 -0
- package/artemis-main/artemis/core/diagnostics/readiness.py +83 -0
- package/artemis-main/artemis/core/diagnostics/schema.py +118 -0
- package/artemis-main/artemis/core/tool_declaration.py +43 -0
- package/artemis-main/artemis/core/tool_failure.py +56 -0
- package/artemis-main/artemis/data_engine/context_vars.py +24 -0
- package/artemis-main/artemis/data_engine/engine.py +1615 -0
- package/artemis-main/artemis/data_engine/history_reader.py +142 -0
- package/artemis-main/artemis/data_engine/models.py +131 -0
- package/artemis-main/artemis/data_engine/storage.py +1245 -0
- package/artemis-main/artemis/data_engine/trace.py +727 -0
- package/artemis-main/artemis/drivers/__init__.py +48 -0
- package/artemis-main/artemis/drivers/android/adb_driver.py +507 -0
- package/artemis-main/artemis/drivers/android/hierarchy.py +64 -0
- package/artemis-main/artemis/drivers/android/input_ime.py +120 -0
- package/artemis-main/artemis/drivers/android/recorder.py +57 -0
- package/artemis-main/artemis/drivers/base.py +290 -0
- package/artemis-main/artemis/drivers/cloud/cloud_driver.py +117 -0
- package/artemis-main/artemis/drivers/factory.py +80 -0
- package/artemis-main/artemis/drivers/mock/mock_driver.py +198 -0
- package/artemis-main/artemis/drivers/types.py +67 -0
- package/artemis-main/artemis/graph/checkpoints.py +1243 -0
- package/artemis-main/artemis/graph/graph.py +1055 -0
- package/artemis-main/artemis/graph/perception.py +234 -0
- package/artemis-main/artemis/graph/state.py +151 -0
- package/artemis-main/artemis/graph/visibility.py +238 -0
- package/artemis-main/artemis/interfaces/cli/__init__.py +19 -0
- package/artemis-main/artemis/interfaces/cli/commands/__init__.py +15 -0
- package/artemis-main/artemis/interfaces/cli/commands/batch.py +278 -0
- package/artemis-main/artemis/interfaces/cli/commands/doctor.py +468 -0
- package/artemis-main/artemis/interfaces/cli/commands/helper.py +226 -0
- package/artemis-main/artemis/interfaces/cli/commands/init.py +193 -0
- package/artemis-main/artemis/interfaces/cli/commands/mcp.py +862 -0
- package/artemis-main/artemis/interfaces/cli/commands/run.py +463 -0
- package/artemis-main/artemis/interfaces/cli/commands/server.py +151 -0
- package/artemis-main/artemis/interfaces/cli/commands/server_lifecycle.py +328 -0
- package/artemis-main/artemis/interfaces/cli/commands/trace.py +111 -0
- package/artemis-main/artemis/interfaces/cli/commands/ui.py +404 -0
- package/artemis-main/artemis/interfaces/cli/main.py +109 -0
- package/artemis-main/artemis/interfaces/sdk/__init__.py +31 -0
- package/artemis-main/artemis/interfaces/sdk/client.py +19 -0
- package/artemis-main/artemis/interfaces/sdk/task.py +72 -0
- package/artemis-main/artemis/llm/__init__.py +25 -0
- package/artemis-main/artemis/llm/fake_model.py +179 -0
- package/artemis-main/artemis/llm/google/__init__.py +57 -0
- package/artemis-main/artemis/llm/google/provider.py +185 -0
- package/artemis-main/artemis/llm/google/usage.py +148 -0
- package/artemis-main/artemis/llm/parser.py +32 -0
- package/artemis-main/artemis/llm/reliability.py +267 -0
- package/artemis-main/artemis/llm/router.py +389 -0
- package/artemis-main/artemis/llm/schemas.py +36 -0
- package/artemis-main/artemis/llm/structured.py +196 -0
- package/artemis-main/artemis/main.py +58 -0
- package/artemis-main/artemis/mcp/__init__.py +20 -0
- package/artemis-main/artemis/mcp/action_executor.py +760 -0
- package/artemis-main/artemis/mcp/action_manifest.py +320 -0
- package/artemis-main/artemis/mcp/action_names.py +172 -0
- package/artemis-main/artemis/mcp/action_server.py +202 -0
- package/artemis-main/artemis/mcp/action_session.py +245 -0
- package/artemis-main/artemis/mcp/action_specs.py +868 -0
- package/artemis-main/artemis/mcp/action_types.py +86 -0
- package/artemis-main/artemis/mcp/actuators/__init__.py +21 -0
- package/artemis-main/artemis/mcp/actuators/adb.py +414 -0
- package/artemis-main/artemis/mcp/actuators/base.py +113 -0
- package/artemis-main/artemis/mcp/actuators/mock.py +70 -0
- package/artemis-main/artemis/mcp/adb_server.py +490 -0
- package/artemis-main/artemis/mcp/observation.py +133 -0
- package/artemis-main/artemis/mcp/xml_search_server.py +297 -0
- package/artemis-main/artemis/memory/__init__.py +90 -0
- package/artemis-main/artemis/memory/chunking.py +1843 -0
- package/artemis-main/artemis/memory/context_policy.py +226 -0
- package/artemis-main/artemis/memory/step_capsule.md +73 -0
- package/artemis-main/artemis/memory/step_memory.py +281 -0
- package/artemis-main/artemis/memory/transcript.py +798 -0
- package/artemis-main/artemis/platform/__init__.py +61 -0
- package/artemis-main/artemis/platform/base.py +104 -0
- package/artemis-main/artemis/platform/darwin.py +184 -0
- package/artemis-main/artemis/platform/linux.py +207 -0
- package/artemis-main/artemis/platform/windows.py +193 -0
- package/artemis-main/artemis/resources/__init__.py +46 -0
- package/artemis-main/artemis/runtime/__init__.py +108 -0
- package/artemis-main/artemis/runtime/adb_endpoint.py +173 -0
- package/artemis-main/artemis/runtime/awake_lease.py +283 -0
- package/artemis-main/artemis/runtime/awake_service.py +343 -0
- package/artemis-main/artemis/runtime/cancel_requests.py +254 -0
- package/artemis-main/artemis/runtime/daemon_client.py +422 -0
- package/artemis-main/artemis/runtime/device_lock.py +1013 -0
- package/artemis-main/artemis/runtime/device_pool.py +478 -0
- package/artemis-main/artemis/runtime/helper_manager.py +1030 -0
- package/artemis-main/artemis/runtime/process_probe.py +98 -0
- package/artemis-main/artemis/runtime/server_lifecycle.py +435 -0
- package/artemis-main/artemis/runtime/supervisor.py +121 -0
- package/artemis-main/artemis/runtime/trace_store.py +375 -0
- package/artemis-main/artemis/sdk/__init__.py +26 -0
- package/artemis-main/artemis/sdk/agent.py +485 -0
- package/artemis-main/artemis/sdk/builders/__init__.py +29 -0
- package/artemis-main/artemis/sdk/builders/agent_config_builder.py +474 -0
- package/artemis-main/artemis/sdk/constants.py +15 -0
- package/artemis-main/artemis/sdk/run_outcome.py +58 -0
- package/artemis-main/artemis/sdk/types/__init__.py +61 -0
- package/artemis-main/artemis/sdk/types/agent.py +89 -0
- package/artemis-main/artemis/sdk/utils.py +28 -0
- package/artemis-main/artemis/services/llm.py +1040 -0
- package/artemis-main/artemis/services/token_meter.py +267 -0
- package/artemis-main/artemis/telemetry/__init__.py +35 -0
- package/artemis-main/artemis/telemetry/models.py +64 -0
- package/artemis-main/artemis/telemetry/replay.py +34 -0
- package/artemis-main/artemis/telemetry/storage/json_storage.py +47 -0
- package/artemis-main/artemis/telemetry/tracer.py +85 -0
- package/artemis-main/artemis/toolchain/__init__.py +52 -0
- package/artemis-main/artemis/toolchain/descriptors.py +92 -0
- package/artemis-main/artemis/toolchain/resolver.py +185 -0
- package/artemis-main/artemis/tools/base.py +232 -0
- package/artemis-main/artemis/tools/command_tool.py +1240 -0
- package/artemis-main/artemis/tools/committee_prompts.json +5 -0
- package/artemis-main/artemis/tools/committee_tool.py +422 -0
- package/artemis-main/artemis/tools/diagnoser_submit_answer_tool.py +87 -0
- package/artemis-main/artemis/tools/diagnostic_tool.py +120 -0
- package/artemis-main/artemis/tools/explorer_tool.py +581 -0
- package/artemis-main/artemis/tools/history/__init__.py +398 -0
- package/artemis-main/artemis/tools/history/replay.py +120 -0
- package/artemis-main/artemis/tools/history/screenshot.py +139 -0
- package/artemis-main/artemis/tools/history/search.py +563 -0
- package/artemis-main/artemis/tools/image_processor_tool.py +124 -0
- package/artemis-main/artemis/tools/index.py +47 -0
- package/artemis-main/artemis/tools/log_tool.py +108 -0
- package/artemis-main/artemis/tools/mobile/launch_app.py +132 -0
- package/artemis-main/artemis/tools/mobile/log_utils.py +138 -0
- package/artemis-main/artemis/tools/mobile/ocr.py +202 -0
- package/artemis-main/artemis/tools/mobile/read_hierarchy.py +108 -0
- package/artemis-main/artemis/tools/mobile/read_logs.py +116 -0
- package/artemis-main/artemis/tools/mobile/search_logs.py +260 -0
- package/artemis-main/artemis/tools/object_detection_tool.py +244 -0
- package/artemis-main/artemis/tools/scratchpad.py +819 -0
- package/artemis-main/artemis/tools/system/adb_shell.py +31 -0
- package/artemis-main/artemis/tools/tool_wrapper.py +270 -0
- package/artemis-main/artemis/tools/video_tool.py +261 -0
- package/artemis-main/artemis/tools/wait_tool.py +97 -0
- package/artemis-main/artemis/utils/app_launch_utils.py +207 -0
- package/artemis-main/artemis/utils/coordinates.py +606 -0
- package/artemis-main/artemis/utils/credentials_validator.py +201 -0
- package/artemis-main/artemis/utils/cv_canvas.py +189 -0
- package/artemis-main/artemis/utils/cython_compat.py +45 -0
- package/artemis-main/artemis/utils/element_hit_test.py +80 -0
- package/artemis-main/artemis/utils/image_diff.py +335 -0
- package/artemis-main/artemis/utils/image_hash.py +80 -0
- package/artemis-main/artemis/utils/notes.py +470 -0
- package/artemis-main/artemis/utils/ocr_api.py +105 -0
- package/artemis-main/artemis/utils/ocr_xml_fusion.py +318 -0
- package/artemis-main/artemis/utils/plan_grammar.py +513 -0
- package/artemis-main/artemis/utils/python_executor.py +213 -0
- package/artemis-main/artemis/utils/startup_progress.py +60 -0
- package/artemis-main/artemis/utils/task_tree.py +1174 -0
- package/artemis-main/artemis/utils/text.py +37 -0
- package/artemis-main/artemis/utils/ui_filter.py +651 -0
- package/artemis-main/artemis/utils/video.py +685 -0
- package/artemis-main/artemis/utils/visualization.py +802 -0
- package/artemis-main/config/artemis.example.jsonc +12 -0
- package/artemis-main/mcp_server/README.md +111 -0
- package/artemis-main/mcp_server/__init__.py +21 -0
- package/artemis-main/mcp_server/__main__.py +20 -0
- package/artemis-main/mcp_server/background/__init__.py +15 -0
- package/artemis-main/mcp_server/background/task_runner.py +453 -0
- package/artemis-main/mcp_server/base.py +49 -0
- package/artemis-main/mcp_server/notifiers/__init__.py +74 -0
- package/artemis-main/mcp_server/notifiers/agentapi.py +289 -0
- package/artemis-main/mcp_server/notifiers/base.py +45 -0
- package/artemis-main/mcp_server/notifiers/composite.py +87 -0
- package/artemis-main/mcp_server/notifiers/desktop.py +108 -0
- package/artemis-main/mcp_server/notifiers/file.py +69 -0
- package/artemis-main/mcp_server/notifiers/script.py +90 -0
- package/artemis-main/mcp_server/notifiers/webhook.py +87 -0
- package/artemis-main/mcp_server/rules.md +68 -0
- package/artemis-main/mcp_server/server.py +106 -0
- package/artemis-main/mcp_server/tools/__init__.py +29 -0
- package/artemis-main/mcp_server/tools/device_state.py +107 -0
- package/artemis-main/mcp_server/tools/diagnose.py +1249 -0
- package/artemis-main/mcp_server/tools/inspect_trace.py +394 -0
- package/artemis-main/mcp_server/tools/task_manager.py +627 -0
- package/artemis-main/mcp_server/tools/task_runner.py +548 -0
- package/artemis-main/mcp_server/utils/__init__.py +15 -0
- package/artemis-main/mcp_server/utils/device_utils.py +180 -0
- package/artemis-main/mcp_server/utils/env_utils.py +65 -0
- package/artemis-main/packages/artemis-accessibility-helper/ArtemisAccessibilityHelper.apk +0 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/build.gradle.kts +35 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/AndroidManifest.xml +49 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/A11yNode.java +274 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/ArtemisAccessibilityService.java +227 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/CommandServer.java +463 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/DisplayUtils.java +111 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/GestureController.java +232 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/HierarchyDumper.java +832 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/TokenReceiver.java +36 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/TokenStore.java +38 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/XmlUtils.java +102 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/res/values/strings.xml +4 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/res/xml/accessibility_service_config.xml +10 -0
- package/artemis-main/packages/artemis-accessibility-helper/build.gradle.kts +3 -0
- package/artemis-main/packages/artemis-accessibility-helper/build_apk.sh +215 -0
- package/artemis-main/packages/artemis-accessibility-helper/debug.keystore +0 -0
- package/artemis-main/packages/artemis-accessibility-helper/gradle.properties +2 -0
- package/artemis-main/packages/artemis-accessibility-helper/helper_manifest.json +7 -0
- package/artemis-main/packages/artemis-accessibility-helper/settings.gradle.kts +17 -0
- package/artemis-main/packages/artemis-client/DESIGN.md +89 -0
- package/artemis-main/packages/artemis-client/README.md +112 -0
- package/artemis-main/packages/artemis-client/examples/basic.py +30 -0
- package/artemis-main/packages/artemis-client/pyproject.toml +36 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/__init__.py +45 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/client.py +401 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/errors.py +66 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/models.py +212 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/py.typed +1 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/transport.py +134 -0
- package/artemis-main/packages/artemis-client/tests/test_client.py +289 -0
- package/artemis-main/packages/artemis-client/tests/test_transport.py +85 -0
- package/artemis-main/pyproject.toml +259 -0
- package/artemis-main/pyright-core.json +17 -0
- package/artemis-main/scripts/check_dependency_sources.py +68 -0
- package/artemis-main/scripts/install_deps.ps1 +520 -0
- package/artemis-main/scripts/install_deps.sh +533 -0
- package/artemis-main/scripts/quality_ratchet.py +97 -0
- package/artemis-main/scripts/real_device_video_acceptance.py +483 -0
- package/artemis-main/scripts/run_edge_case_part.py +327 -0
- package/artemis-main/scripts/run_ui.py +242 -0
- package/artemis-main/scripts/start.ps1 +500 -0
- package/artemis-main/scripts/test_all_edge_cases.py +269 -0
- package/artemis-main/scripts/verify_concurrency_and_devices.py +385 -0
- package/artemis-main/setup.py +164 -0
- package/artemis-main/start.bat +35 -0
- package/artemis-main/start.sh +423 -0
- package/artemis-main/third_party/mobile_use/LICENSE +190 -0
- package/artemis-main/third_party/mobile_use/METADATA +27 -0
- package/artemis-main/third_party/mobile_use/NOTICE +12 -0
- package/artemis-main/third_party/mobile_use/__init__.py +19 -0
- package/artemis-main/third_party/mobile_use/agents/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/agents/hopper/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/agents/hopper/hopper.md +22 -0
- package/artemis-main/third_party/mobile_use/agents/hopper/hopper.py +80 -0
- package/artemis-main/third_party/mobile_use/clients/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/clients/ui_automator_client.py +482 -0
- package/artemis-main/third_party/mobile_use/config/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/config/llm.py +183 -0
- package/artemis-main/third_party/mobile_use/config/output.py +184 -0
- package/artemis-main/third_party/mobile_use/context.py +119 -0
- package/artemis-main/third_party/mobile_use/controllers/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/controllers/platform_specific_commands_controller.py +151 -0
- package/artemis-main/third_party/mobile_use/controllers/types.py +92 -0
- package/artemis-main/third_party/mobile_use/controllers/unified_controller.py +183 -0
- package/artemis-main/third_party/mobile_use/graph.py +54 -0
- package/artemis-main/third_party/mobile_use/llm_service.py +193 -0
- package/artemis-main/third_party/mobile_use/main.py +130 -0
- package/artemis-main/third_party/mobile_use/sdk/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/sdk/agent.py +1060 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/agent_config_builder.py +225 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/index.py +33 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/task_request_builder.py +243 -0
- package/artemis-main/third_party/mobile_use/sdk/types/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/sdk/types/agent.py +98 -0
- package/artemis-main/third_party/mobile_use/sdk/types/exceptions.py +109 -0
- package/artemis-main/third_party/mobile_use/sdk/types/task.py +234 -0
- package/artemis-main/third_party/mobile_use/testing.py +59 -0
- package/artemis-main/third_party/mobile_use/tools/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/tools/index.py +44 -0
- package/artemis-main/third_party/mobile_use/tools/mobile/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/tools/mobile/launch_app.py +89 -0
- package/artemis-main/third_party/mobile_use/tools/tool_wrapper.py +52 -0
- package/artemis-main/third_party/mobile_use/utils/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/utils/app_launch_utils.py +217 -0
- package/artemis-main/third_party/mobile_use/utils/cli_helpers.py +60 -0
- package/artemis-main/third_party/mobile_use/utils/decorators.py +158 -0
- package/artemis-main/third_party/mobile_use/utils/file.py +31 -0
- package/artemis-main/third_party/mobile_use/utils/logger.py +216 -0
- package/artemis-main/third_party/mobile_use/utils/media.py +213 -0
- package/artemis-main/third_party/mobile_use/utils/shell_utils.py +39 -0
- package/artemis-main/third_party/mobile_use/utils/video.py +398 -0
- package/artemis-main/uv.lock +4908 -0
- package/bin/android-midscene-automation.js +1 -5
- package/bin/artemis-config.mjs +15 -0
- package/bin/artemis-embedded.py +56 -0
- package/bin/start-artemis.mjs +30 -0
- package/bin/start-dev.mjs +112 -0
- package/bin/test_artemis_embedded.py +44 -0
- package/package.json +10 -8
- package/server/artemis.ts +34 -0
- package/server/http-api.ts +13 -1
- package/src/App.vue +72 -23
- package/src/api.ts +5 -0
- package/src/appium-recorder/AppiumPage.vue +1 -1
- package/src/appium-recorder/components/ComponentInspector.vue +1 -1
- package/src/appium-recorder/components/FlowNodeSearch.vue +3 -3
- package/src/appium-recorder/components/ImageCheckDialog.vue +3 -3
- package/src/appium-recorder/components/RecorderWorkspace.vue +4 -4
- package/src/appium-recorder/flow-appearance.ts +4 -4
- package/src/components/AppSidebar.vue +8 -7
- package/src/components/MidsceneMaintenanceNotice.vue +17 -0
- package/src/components/analytics/AnalysisCharts.vue +4 -4
- package/src/components/analytics/ReportAnalysis.vue +1 -1
- package/src/components/generator/TestCaseFileUpload.vue +1 -1
- package/src/components/help/HelpCenter.vue +56 -37
- package/src/pages/AiGeneratorPage.vue +1 -1
- package/src/pages/ArtemisPage.vue +72 -0
- package/src/pages/ConfigPage.vue +18 -19
- package/src/style.css +369 -186
- package/src/types.ts +1 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Public defaults only. Put API keys and endpoint URLs in .env.
|
|
3
|
+
// The launcher copies this template to artemis.jsonc only if it is missing.
|
|
4
|
+
"default": {
|
|
5
|
+
"provider": "google",
|
|
6
|
+
"model": "gemini-2.5-flash",
|
|
7
|
+
"fallback": {
|
|
8
|
+
"provider": "google",
|
|
9
|
+
"model": "gemini-2.0-flash"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# 🔌 Universal MCP Server for ARTEMIS
|
|
2
|
+
|
|
3
|
+
This directory contains the **Model Context Protocol (MCP)** server for **ARTEMIS**. It exposes mobile device automation to clients such as **Antigravity**, **Cursor**, **Claude Code**, **OpenClaw**, and **Windsurf**.
|
|
4
|
+
|
|
5
|
+
## 🏗️ Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
mcp_server/
|
|
9
|
+
├── __init__.py # Package exports (mcp, main)
|
|
10
|
+
├── base.py # Shared FastMCP instance
|
|
11
|
+
├── server.py # Server entrypoint (stdio / sse)
|
|
12
|
+
├── rules.md # AI Agent Testing Mindset & system prompt rules for IDEs
|
|
13
|
+
├── background/ # Background process execution
|
|
14
|
+
│ └── task_runner.py # Subprocess runner for Artemis Agent
|
|
15
|
+
├── notifiers/ # Multi-environment notification adapters
|
|
16
|
+
│ ├── base.py # BaseNotifier abstract class
|
|
17
|
+
│ ├── agentapi.py # Jetski / Antigravity AgentAPI notifier (with session sorting & caching)
|
|
18
|
+
│ ├── desktop.py # Native OS toast notifier (macOS/Linux/Windows, enabled by default)
|
|
19
|
+
│ ├── script.py # Universal Script / Command Hook notifier (ARTEMIS_NOTIFY_CMD)
|
|
20
|
+
│ ├── webhook.py # OpenClaw / CI / Discord / Slack webhook notifier
|
|
21
|
+
│ ├── file.py # File audit logger (notifications.jsonl)
|
|
22
|
+
│ └── composite.py # Multi-channel notification dispatcher
|
|
23
|
+
├── tools/ # Modular standard MCP tools
|
|
24
|
+
│ ├── task_runner.py # mobile_run_task
|
|
25
|
+
│ ├── task_manager.py # mobile_manage_task
|
|
26
|
+
│ ├── device_state.py # mobile_get_device_state
|
|
27
|
+
│ ├── inspect_trace.py # mobile_inspect_trace
|
|
28
|
+
│ └── diagnose.py # mobile_diagnose
|
|
29
|
+
└── utils/ # Environment and device utilities
|
|
30
|
+
├── device_utils.py # Cross-platform ADB and emulator resolver
|
|
31
|
+
└── env_utils.py # Python interpreter and process manager
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The trace status store (traces directory layout and `status.json` lifecycle)
|
|
35
|
+
lives in the neutral base package as `artemis/runtime/trace_store.py`, shared
|
|
36
|
+
by the MCP server, the admin console, and spawned worker processes.
|
|
37
|
+
|
|
38
|
+
## 🔔 Multi-Platform Notification & Wakeup Support
|
|
39
|
+
|
|
40
|
+
When you start an asynchronous mobile test via `mobile_run_task`, Artemis MCP runs the job as a detached background process so the AI agent is not blocked. Upon completion or failure, Artemis dispatches alerts across **all available notification channels** so that both human developers and AI agents are notified immediately across different platforms:
|
|
41
|
+
|
|
42
|
+
| Platform / Environment | Primary Notification Mechanism | How It Works & Configuration |
|
|
43
|
+
| :--- | :--- | :--- |
|
|
44
|
+
| **Antigravity / Jetski** | **Reactive Wakeup (`AgentApiNotifier`)** | Automatically detects and caches the active IDE session credentials (`ANTIGRAVITY_LS_ADDRESS`, `ANTIGRAVITY_CSRF_TOKEN`), sorting candidate processes by creation time to avoid stale PIDs, and calls `agentapi send-message` to wake up the agent directly in the conversation. |
|
|
45
|
+
| **Cursor / Windsurf / VS Code / Cline / Roo Code** | **Native Desktop Toast (`DesktopNotifier`) + File Audit (`FileNotifier`)** | Enabled **by default** across macOS (`osascript`), Linux (`notify-send`), and Windows (`powershell`). Pops up a system notification banner informing the developer whether the task completed or failed. The AI agent inspects `<trace_dir>/status.json` or uses `mobile_manage_task(action="status")`. Can be silenced via `ARTEMIS_DESKTOP_NOTIFY=false`. |
|
|
46
|
+
| **Claude Code / Desktop** | **Native Desktop Toast + File Audit** | Alerts the user via system desktop notification banner when background execution concludes, while maintaining a complete JSONL audit log in `notifications.jsonl`. |
|
|
47
|
+
| **OpenClaw / Slack / Discord / CI/CD** | **HTTP Webhook (`WebhookNotifier`)** | Sends structured JSON POST payloads to custom endpoints configured via `OPENCLAW_WEBHOOK_URL`, `MCP_NOTIFICATION_WEBHOOK`, or `ARTEMIS_WEBHOOK_URL`. |
|
|
48
|
+
| **Universal Custom IDE / CLI Hooks** | **Custom Script Hook (`ScriptNotifier`)** | Set `ARTEMIS_NOTIFY_CMD="my-script --title '{title}' --message '{message}' --trace-id '{trace_id}'"` in your environment to execute any custom command or script upon event completion. |
|
|
49
|
+
|
|
50
|
+
## 🧠 AI Agent Behavioral Rules (`rules.md`)
|
|
51
|
+
|
|
52
|
+
When connecting ARTEMIS to AI coding assistants like **Antigravity**, **Claude Code**, **Cursor**, or **Windsurf**, providing the assistant with domain-specific testing discipline is critical for generating reliable test code.
|
|
53
|
+
|
|
54
|
+
The included [`rules.md`](./rules.md) file contains the **Mobile Testing Mindset (ARTEMIS Integration)** guideline. It teaches the AI agent how to properly collaborate with ARTEMIS:
|
|
55
|
+
|
|
56
|
+
1. **The Runnable Code Principle & Active Exploration**: Instructs the AI to never guess or hallucinate UI transitions. Instead, it must first explore the live app via ARTEMIS MCP tools (`mobile_run_task`, etc.) to discover and verify real-world interaction paths before writing test scripts.
|
|
57
|
+
2. **Flash vs. Pro Routing Strategy**: Guides the AI to choose **Flash** for rapid, straightforward UI actions (no step cap by default) and **Pro** for tasks that need a persistent plan, verified checkpoints, polling loops, or ADB / video / log diagnosis.
|
|
58
|
+
3. **Latency & Timing Compensation**: Clarifies the difference between AI exploratory latency (e.g., model decision intervals) and the deterministic timing requirements of final test code.
|
|
59
|
+
4. **"Dynamic-First, Coordinate-Fallback" Locator Pattern**: Teaches the AI to prioritize dynamic UI locators (Resource IDs, OCR text, semantics) for layout resilience, while implementing absolute coordinate fallbacks for maximum execution reliability.
|
|
60
|
+
5. **Environment Self-Diagnosis**: Tells the AI to call `mobile_diagnose` first whenever a tool errors or the user says ARTEMIS is not working, and how to act on the returned fix list (run local commands itself, relay device prompts to the user, never move API keys through the chat, reload the MCP server after config changes).
|
|
61
|
+
|
|
62
|
+
### How Global Rules & MCP are Installed
|
|
63
|
+
When you run `uv run artemis mcp --install all` (or target a specific IDE like `--install cursor`, `--install claude`, etc.), the installer **automatically synchronizes both global MCP server configuration and global testing rules** into the corresponding user home directories (without creating project-level rule files in your workspace):
|
|
64
|
+
* **Antigravity / Jetski**: Automatically installs global rules to `~/.gemini/rules/artemis.md`.
|
|
65
|
+
* **Cursor**: Automatically installs global YAML-frontmatter rule file at `~/.cursor/rules/artemis.mdc`.
|
|
66
|
+
* **Claude Code / Desktop**: Automatically installs global rules to `~/.claude/rules/artemis.md`.
|
|
67
|
+
* **Windsurf**: Automatically installs global rules to `~/.codeium/windsurf/rules/artemis.md`.
|
|
68
|
+
* **VS Code**: Automatically installs global rules to `~/.vscode/rules/artemis.md`.
|
|
69
|
+
* **Cline / Roo Code**: Automatically installs global rules to `~/.cline/rules/artemis.md` and `~/.roo/rules/artemis.md`.
|
|
70
|
+
* **OpenClaw**: Automatically installs global rules to `~/.openclaw/rules/artemis.md`.
|
|
71
|
+
|
|
72
|
+
*(Note: If you prefer manual configuration, you can also copy the contents of [`rules.md`](./rules.md) into your IDE's system prompt or global rules settings.)*
|
|
73
|
+
|
|
74
|
+
## 🛠️ MCP Tools Overview
|
|
75
|
+
|
|
76
|
+
* **`mobile_run_task`**: Asynchronously launches an autonomous mobile automation task (`Flash` or `Pro` model) with optional `device_serial` targeting. Pro runs can be tuned with `verification_level` (`off` | `final` | `checkpoints` | `strict` — how much the Checker audits) and `explorer_mode` (`flash` | `pro` | `ultra` — the Operator's perception depth).
|
|
77
|
+
* **`mobile_manage_task`**: Manages task lifecycle (`status`, `stop`, `inject_instruction`), returning task state and assigned `device_serial`. Pass `release_loop=True` with `inject_instruction` to gracefully end a `[Loop:continuous]` monitoring task — this explicit signal (not "please stop" wording) is what unlocks the loop milestone's completion.
|
|
78
|
+
* **`mobile_get_device_state`**: Real-time observer (`screenshot` or OCR+XML `hierarchy`) with optional `device_serial`.
|
|
79
|
+
* **`mobile_inspect_trace`**: Granular trace inspection, visual action overlays, agent reasoning, and `device_serial` tracking.
|
|
80
|
+
* **`mobile_diagnose`**: Environment doctor for the IDE. Reuses the readiness probes behind `artemis doctor` and the web console's device wizard (Python runtime, config, LLM credentials, ADB / devices / RSA keys / emulators, video toolchain) plus an MCP-host probe (server interpreter vs project `.venv`, detected MCP client, `.env` location, traces directory, daemon port collisions). Returns a `verdict` (`ready` | `degraded` | `blocked`), an ordered `next_steps` fix list the AI agent can act on (`Run:` one-command lines vs `Guidance:` for the user), scrubbed per-check details, `tasks` holding or waiting for devices, log paths, and the most recent failed task with its `recent_errors`. Optional deep checks: `verify_credentials=true` (live API-key validation, ~12s, result in `credentials`), `probe_device=true` (end-to-end screenshot + UIAutomator hierarchy, ~20s, result in `device_probe`), `launch_avd="<name>"` (boots an installed AVD in the background; re-run after ~60s). `attempt_fix=true` applies the safe self-heals (regenerate corrupted ADB keys, restart the ADB server, clear stale device locks / queue tickets left by crashed runners).
|
|
81
|
+
|
|
82
|
+
### 📱 Device Selection & Multi-Device Execution
|
|
83
|
+
ARTEMIS supports parallel execution across multiple connected Android devices and emulators:
|
|
84
|
+
1. **Direct Device Specification**: Provide `device_serial` explicitly (e.g. `device_serial="63191FDKX00062"` or `device_serial="emulator-5554"`). Per-device execution locks allow distinct devices to run in parallel.
|
|
85
|
+
2. **Automatic Device Selection**: Omit `device_serial` to let ARTEMIS auto-select an available ready device from the device pool.
|
|
86
|
+
* **User Choice Priority**: When multiple devices/emulators are connected, AI agents should prioritize asking the user which device to run on.
|
|
87
|
+
* **Device Diagnosis**: Inspect connected hardware, authorization status, and serials anytime via `adb devices` or `adb devices -l`.
|
|
88
|
+
|
|
89
|
+
## 🚀 How to Run & Configure
|
|
90
|
+
|
|
91
|
+
### CLI Execution
|
|
92
|
+
```bash
|
|
93
|
+
# Start server over stdio
|
|
94
|
+
python -m mcp_server
|
|
95
|
+
|
|
96
|
+
# Or via Artemis CLI
|
|
97
|
+
uv run artemis mcp
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### IDE Configuration
|
|
101
|
+
|
|
102
|
+
#### One-Click Auto Install (Recommended)
|
|
103
|
+
Run the automated installer to detect and configure your IDE (Antigravity, Cursor, Claude Code/Desktop, OpenClaw):
|
|
104
|
+
```bash
|
|
105
|
+
uv run artemis mcp --install all
|
|
106
|
+
# Or install specifically for Antigravity:
|
|
107
|
+
uv run artemis mcp --install antigravity
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Manual JSON Config Generation
|
|
111
|
+
Run `uv run artemis mcp --generate-config antigravity` (or `all`) to output ready-to-use configuration JSON with resolved `.venv` Python and project paths.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Copyright 2026 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Universal Model Context Protocol (MCP) Server for ARTEMIS."""
|
|
16
|
+
|
|
17
|
+
from mcp_server.base import mcp
|
|
18
|
+
from mcp_server.server import main
|
|
19
|
+
import mcp_server.tools # noqa: F401
|
|
20
|
+
|
|
21
|
+
__all__ = ["mcp", "main"]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Copyright 2026 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Direct execution entrypoint for mcp_server."""
|
|
16
|
+
|
|
17
|
+
from mcp_server.server import main
|
|
18
|
+
|
|
19
|
+
if __name__ == "__main__":
|
|
20
|
+
main()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2026 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""MCP Background execution package."""
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Copyright 2026 Google LLC
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""Background execution runner for MCP autonomous mobile automation tasks."""
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import asyncio
|
|
20
|
+
import json
|
|
21
|
+
import logging
|
|
22
|
+
import os
|
|
23
|
+
import sys
|
|
24
|
+
import traceback
|
|
25
|
+
|
|
26
|
+
from dotenv import load_dotenv
|
|
27
|
+
|
|
28
|
+
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
29
|
+
if PROJECT_ROOT not in sys.path:
|
|
30
|
+
sys.path.insert(0, PROJECT_ROOT)
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
from artemis.config.paths import get_app_dir
|
|
34
|
+
|
|
35
|
+
app_dir = str(get_app_dir())
|
|
36
|
+
global_env = os.path.join(app_dir, ".env")
|
|
37
|
+
if os.path.exists(global_env):
|
|
38
|
+
load_dotenv(global_env)
|
|
39
|
+
else:
|
|
40
|
+
load_dotenv(os.path.join(PROJECT_ROOT, ".env"))
|
|
41
|
+
except Exception:
|
|
42
|
+
load_dotenv(os.path.join(PROJECT_ROOT, ".env"))
|
|
43
|
+
|
|
44
|
+
from artemis.runtime import trace_store
|
|
45
|
+
from mcp_server.notifiers import notify
|
|
46
|
+
from mcp_server.utils import device_utils
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
async def _initialize_agent(
|
|
50
|
+
agent,
|
|
51
|
+
*,
|
|
52
|
+
retry_count: int,
|
|
53
|
+
retry_wait_seconds: int,
|
|
54
|
+
timeout_seconds: float,
|
|
55
|
+
) -> None:
|
|
56
|
+
"""Initialize one SDK agent without allowing a detached runner to hang forever."""
|
|
57
|
+
try:
|
|
58
|
+
await asyncio.wait_for(
|
|
59
|
+
agent.init(
|
|
60
|
+
retry_count=retry_count,
|
|
61
|
+
retry_wait_seconds=retry_wait_seconds,
|
|
62
|
+
),
|
|
63
|
+
timeout=timeout_seconds,
|
|
64
|
+
)
|
|
65
|
+
except TimeoutError as error:
|
|
66
|
+
raise TimeoutError(
|
|
67
|
+
"Artemis Agent initialization exceeded "
|
|
68
|
+
f"{timeout_seconds:.1f}s; check ADB/UIAutomator health and the device queue."
|
|
69
|
+
) from error
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def resolve_profile_file() -> str | None:
|
|
73
|
+
"""Resolves the LLM configuration profile across multiple locations."""
|
|
74
|
+
candidates = []
|
|
75
|
+
artemis_config_dir = os.getenv("ARTEMIS_CONFIG_DIR")
|
|
76
|
+
if artemis_config_dir:
|
|
77
|
+
candidates.extend(
|
|
78
|
+
[
|
|
79
|
+
os.path.join(artemis_config_dir, "llm-config.override.jsonc"),
|
|
80
|
+
os.path.join(artemis_config_dir, "llm-config.json"),
|
|
81
|
+
]
|
|
82
|
+
)
|
|
83
|
+
try:
|
|
84
|
+
# Deliberate guarded import mirroring the module-level bootstrap above:
|
|
85
|
+
# profile resolution must degrade to repo-relative candidates when the
|
|
86
|
+
# artemis config package cannot be loaded.
|
|
87
|
+
from artemis.config.paths import get_app_dir
|
|
88
|
+
|
|
89
|
+
app_dir = str(get_app_dir())
|
|
90
|
+
candidates.extend(
|
|
91
|
+
[
|
|
92
|
+
os.path.join(app_dir, "llm-config.override.jsonc"),
|
|
93
|
+
os.path.join(app_dir, "llm-config.json"),
|
|
94
|
+
]
|
|
95
|
+
)
|
|
96
|
+
except (ImportError, OSError):
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
candidates.extend(
|
|
100
|
+
[
|
|
101
|
+
os.path.join(PROJECT_ROOT, "llm-config.override.jsonc"),
|
|
102
|
+
os.path.join(PROJECT_ROOT, "llm-config.json"),
|
|
103
|
+
os.path.join(PROJECT_ROOT, "config", "llm-config.json"),
|
|
104
|
+
]
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
for cand in candidates:
|
|
108
|
+
if os.path.exists(cand):
|
|
109
|
+
return cand
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
async def run_task(
|
|
114
|
+
trace_id: str,
|
|
115
|
+
task_desc: str,
|
|
116
|
+
model: str,
|
|
117
|
+
conversation_id: str,
|
|
118
|
+
locked_app_package: str | None = None,
|
|
119
|
+
app_path: str | None = None,
|
|
120
|
+
expected_output_desc: str | None = None,
|
|
121
|
+
device_serial: str | None = None,
|
|
122
|
+
verification_level: str | None = None,
|
|
123
|
+
explorer_pro_mode: str | None = None,
|
|
124
|
+
):
|
|
125
|
+
"""Executes the mobile automation agent task and logs all actions/results.
|
|
126
|
+
|
|
127
|
+
``verification_level`` ('off' | 'final' | 'checkpoints' | 'strict') and
|
|
128
|
+
``explorer_pro_mode`` ('flash' | 'pro' | 'ultra') are Pro-profile tuning
|
|
129
|
+
knobs mirroring ``artemis run --verification-level / --explorer-pro-mode``;
|
|
130
|
+
the Flash profile ignores them.
|
|
131
|
+
"""
|
|
132
|
+
trace_dir = trace_store.get_trace_dir(trace_id)
|
|
133
|
+
os.makedirs(trace_dir, exist_ok=True)
|
|
134
|
+
stdout_log_path = os.path.join(trace_dir, "stdout.log")
|
|
135
|
+
stderr_log_path = os.path.join(trace_dir, "stderr.log")
|
|
136
|
+
|
|
137
|
+
original_stdout = sys.stdout
|
|
138
|
+
original_stderr = sys.stderr
|
|
139
|
+
|
|
140
|
+
log_file_out = open(stdout_log_path, "w", buffering=1, encoding="utf-8")
|
|
141
|
+
log_file_err = open(stderr_log_path, "w", buffering=1, encoding="utf-8")
|
|
142
|
+
|
|
143
|
+
sys.stdout = log_file_out
|
|
144
|
+
sys.stderr = log_file_err
|
|
145
|
+
|
|
146
|
+
logging.basicConfig(level=logging.INFO, force=True)
|
|
147
|
+
logging.getLogger("absl").setLevel(logging.WARNING)
|
|
148
|
+
logging.getLogger("artemis").setLevel(logging.INFO)
|
|
149
|
+
|
|
150
|
+
print(f"Starting task execution for Trace ID: {trace_id}")
|
|
151
|
+
print(f"Goal: {task_desc}")
|
|
152
|
+
print(f"Model: {model}")
|
|
153
|
+
print(f"Conversation ID: {conversation_id}")
|
|
154
|
+
print("--------------------------------------------------")
|
|
155
|
+
|
|
156
|
+
agent = None
|
|
157
|
+
adb_path = device_utils.resolve_adb_path()
|
|
158
|
+
target_serial = device_serial
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
# Deliberate lazy imports: the SDK pulls in the full agent stack
|
|
162
|
+
# (LLM clients, graph, drivers), and importing it inside this try
|
|
163
|
+
# converts an import-time failure into a properly recorded task
|
|
164
|
+
# failure (trace status + wakeup notification) instead of a crash
|
|
165
|
+
# before status.json is ever updated.
|
|
166
|
+
from artemis.config import settings
|
|
167
|
+
from artemis.sdk import Agent
|
|
168
|
+
from artemis.sdk.builders import Builders
|
|
169
|
+
from artemis.sdk.types import AgentProfile
|
|
170
|
+
|
|
171
|
+
connected_devices = device_utils.get_connected_devices(adb_path)
|
|
172
|
+
|
|
173
|
+
if device_serial:
|
|
174
|
+
target_serial = device_serial
|
|
175
|
+
if connected_devices and device_serial not in connected_devices:
|
|
176
|
+
print(
|
|
177
|
+
f"⚠️ Warning: Specified device serial '{device_serial}' was not detected in active ADB devices: {connected_devices}. "
|
|
178
|
+
"Proceeding with target serial (will attempt direct ADB connection)..."
|
|
179
|
+
)
|
|
180
|
+
else:
|
|
181
|
+
print(f"✅ Using specified target device: '{device_serial}'.")
|
|
182
|
+
else:
|
|
183
|
+
if connected_devices:
|
|
184
|
+
target_serial = settings.ADB_DEVICE_SERIAL or os.environ.get("ADB_DEVICE_SERIAL")
|
|
185
|
+
if not target_serial:
|
|
186
|
+
try:
|
|
187
|
+
# Optional path: pool-based selection falls back to the
|
|
188
|
+
# first connected device on any import or query failure.
|
|
189
|
+
from artemis.runtime import device_pool
|
|
190
|
+
|
|
191
|
+
target_serial = device_pool.select_device()
|
|
192
|
+
except Exception:
|
|
193
|
+
target_serial = connected_devices[0]
|
|
194
|
+
print(
|
|
195
|
+
f"✅ Detected active connected device(s): {connected_devices}. "
|
|
196
|
+
f"Auto-selected device: '{target_serial}'."
|
|
197
|
+
)
|
|
198
|
+
else:
|
|
199
|
+
print("❌ No active connected devices detected. Booting emulator...")
|
|
200
|
+
if not device_utils.ensure_emulator(adb_path=adb_path):
|
|
201
|
+
raise RuntimeError("Failed to start or connect to the Android emulator.")
|
|
202
|
+
target_serial = "emulator-5554"
|
|
203
|
+
|
|
204
|
+
if target_serial:
|
|
205
|
+
trace_store.update_trace_device_serial(trace_id, target_serial)
|
|
206
|
+
|
|
207
|
+
print("Initializing Artemis Agent...")
|
|
208
|
+
from artemis.config import initialize_llm_config, settings
|
|
209
|
+
|
|
210
|
+
profile_file = resolve_profile_file()
|
|
211
|
+
if profile_file:
|
|
212
|
+
profile = AgentProfile(name="default", from_file=profile_file)
|
|
213
|
+
else:
|
|
214
|
+
profile = AgentProfile(name="default", llm_config=initialize_llm_config())
|
|
215
|
+
|
|
216
|
+
config_builder = Builders.AgentConfig.with_default_profile(profile)
|
|
217
|
+
if verification_level:
|
|
218
|
+
config_builder.with_verification_level(verification_level)
|
|
219
|
+
if explorer_pro_mode:
|
|
220
|
+
config_builder.with_explorer(pro_mode=explorer_pro_mode)
|
|
221
|
+
if settings.ADB_HOST:
|
|
222
|
+
config_builder.with_adb_server(host=settings.ADB_HOST, port=settings.ADB_PORT)
|
|
223
|
+
|
|
224
|
+
if target_serial:
|
|
225
|
+
from artemis.context import DevicePlatform
|
|
226
|
+
|
|
227
|
+
config_builder.for_device(DevicePlatform.ANDROID, target_serial)
|
|
228
|
+
|
|
229
|
+
config = config_builder.build()
|
|
230
|
+
|
|
231
|
+
agent = Agent(config=config)
|
|
232
|
+
await _initialize_agent(
|
|
233
|
+
agent,
|
|
234
|
+
retry_count=int(os.getenv("ARTEMIS_HEALTH_RETRIES", 5)),
|
|
235
|
+
retry_wait_seconds=int(os.getenv("ARTEMIS_HEALTH_DELAY", 2)),
|
|
236
|
+
timeout_seconds=float(os.getenv("ARTEMIS_AGENT_INIT_TIMEOUT_SECONDS", 30)),
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
actual_serial = (
|
|
240
|
+
getattr(getattr(agent, "_device_context", None), "device_id", None) or target_serial
|
|
241
|
+
)
|
|
242
|
+
if actual_serial:
|
|
243
|
+
target_serial = actual_serial
|
|
244
|
+
trace_store.update_trace_device_serial(trace_id, actual_serial)
|
|
245
|
+
print(f"📱 Bound to device serial: '{actual_serial}'")
|
|
246
|
+
|
|
247
|
+
print("Running task on agent...")
|
|
248
|
+
task_builder = (
|
|
249
|
+
agent.new_task(goal=task_desc)
|
|
250
|
+
.with_name(f"task_{trace_id}")
|
|
251
|
+
.with_trace_recording(enabled=True, path=trace_store.TRACES_DIR)
|
|
252
|
+
)
|
|
253
|
+
if locked_app_package:
|
|
254
|
+
task_builder.with_locked_app_package(package_name=locked_app_package)
|
|
255
|
+
if app_path:
|
|
256
|
+
task_builder.with_app_path(app_path=app_path)
|
|
257
|
+
if expected_output_desc:
|
|
258
|
+
task_builder.with_output_description(description=expected_output_desc)
|
|
259
|
+
if model.lower() == "flash":
|
|
260
|
+
task_builder.using_profile("flash")
|
|
261
|
+
|
|
262
|
+
result = await agent.run_task(request=task_builder.build())
|
|
263
|
+
print(f"Task completed. Result: {result}")
|
|
264
|
+
|
|
265
|
+
device_info_line = f"Device Serial: `{target_serial}`\n" if target_serial else ""
|
|
266
|
+
|
|
267
|
+
if isinstance(result, dict) and "status" in result and result.get("status") != "completed":
|
|
268
|
+
error_explanation = result.get("explanation", "Task execution returned failed status.")
|
|
269
|
+
print(f"Task finished with non-completed status: {error_explanation}", file=sys.stderr)
|
|
270
|
+
trace_store.update_trace_status(
|
|
271
|
+
trace_id,
|
|
272
|
+
"failed",
|
|
273
|
+
error=error_explanation,
|
|
274
|
+
result=result,
|
|
275
|
+
device_serial=target_serial,
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
formatted_result = json.dumps(result, indent=2, ensure_ascii=False)
|
|
279
|
+
failure_msg = (
|
|
280
|
+
f"Artemis background task finished with non-completed status.\n\n"
|
|
281
|
+
f"Trace ID: {trace_id}\n"
|
|
282
|
+
f"{device_info_line}"
|
|
283
|
+
f"Goal: {task_desc}\n"
|
|
284
|
+
f"Explanation: {error_explanation}\n\n"
|
|
285
|
+
f"Result:\n```json\n{formatted_result}\n```\n\n"
|
|
286
|
+
f'Check the logs using mobile_inspect_trace(action="view_summary", trace_id="{trace_id}") '
|
|
287
|
+
f"or inspect stderr log: [stderr.log](file://{stderr_log_path})."
|
|
288
|
+
)
|
|
289
|
+
notify(
|
|
290
|
+
conversation_id=conversation_id,
|
|
291
|
+
message=failure_msg,
|
|
292
|
+
title="Artemis Task Incomplete",
|
|
293
|
+
event_type="failed",
|
|
294
|
+
payload={
|
|
295
|
+
"trace_id": trace_id,
|
|
296
|
+
"device_serial": target_serial,
|
|
297
|
+
"goal": task_desc,
|
|
298
|
+
"result": result,
|
|
299
|
+
},
|
|
300
|
+
)
|
|
301
|
+
return
|
|
302
|
+
|
|
303
|
+
if not result:
|
|
304
|
+
if model.lower() == "flash":
|
|
305
|
+
result = "Task executed successfully."
|
|
306
|
+
else:
|
|
307
|
+
result = (
|
|
308
|
+
"Task executed successfully. You can check the notes under "
|
|
309
|
+
"notes_dir to view more details."
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
trace_store.update_trace_status(
|
|
313
|
+
trace_id, "completed", result=result, device_serial=target_serial
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
if isinstance(result, dict):
|
|
317
|
+
formatted_result = json.dumps(result, indent=2, ensure_ascii=False)
|
|
318
|
+
result_str = f"Result:\n```json\n{formatted_result}\n```\n"
|
|
319
|
+
else:
|
|
320
|
+
formatted_result = str(result)
|
|
321
|
+
result_str = f"Result: {formatted_result}\n"
|
|
322
|
+
|
|
323
|
+
success_msg = (
|
|
324
|
+
"Artemis background task completed successfully.\n\n"
|
|
325
|
+
f"Trace ID: {trace_id}\n"
|
|
326
|
+
f"{device_info_line}"
|
|
327
|
+
f"Goal: {task_desc}\n"
|
|
328
|
+
f"{result_str}"
|
|
329
|
+
)
|
|
330
|
+
notify(
|
|
331
|
+
conversation_id=conversation_id,
|
|
332
|
+
message=success_msg,
|
|
333
|
+
title="Artemis Task Completed",
|
|
334
|
+
event_type="completed",
|
|
335
|
+
payload={
|
|
336
|
+
"trace_id": trace_id,
|
|
337
|
+
"device_serial": target_serial,
|
|
338
|
+
"goal": task_desc,
|
|
339
|
+
"result": result,
|
|
340
|
+
},
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
except asyncio.CancelledError:
|
|
344
|
+
print("Task was cancelled (asyncio.CancelledError)", file=sys.stderr)
|
|
345
|
+
trace_store.update_trace_status(
|
|
346
|
+
trace_id, "cancelled", error="Task was cancelled", device_serial=target_serial
|
|
347
|
+
)
|
|
348
|
+
device_info_line = f"Device Serial: `{target_serial}`\n" if target_serial else ""
|
|
349
|
+
cancel_msg = f"Artemis background task was cancelled.\n\nTrace ID: {trace_id}\n{device_info_line}Goal: {task_desc}\n"
|
|
350
|
+
notify(
|
|
351
|
+
conversation_id=conversation_id,
|
|
352
|
+
message=cancel_msg,
|
|
353
|
+
title="Artemis Task Cancelled",
|
|
354
|
+
event_type="cancelled",
|
|
355
|
+
payload={"trace_id": trace_id, "device_serial": target_serial, "goal": task_desc},
|
|
356
|
+
)
|
|
357
|
+
raise
|
|
358
|
+
|
|
359
|
+
except Exception as e:
|
|
360
|
+
error_type = type(e).__name__
|
|
361
|
+
raw_error_msg = str(e)
|
|
362
|
+
tb_str = traceback.format_exc()
|
|
363
|
+
print(
|
|
364
|
+
f"CRITICAL ERROR during task execution: {error_type}: {raw_error_msg}\n{tb_str}",
|
|
365
|
+
file=sys.stderr,
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
exc_type, exc_obj, tb = sys.exc_info()
|
|
369
|
+
while tb and tb.tb_next:
|
|
370
|
+
tb = tb.tb_next
|
|
371
|
+
frame_summary = f" (at {tb.tb_frame.f_code.co_name}:{tb.tb_lineno})" if tb else ""
|
|
372
|
+
full_error_desc = f"{error_type}: {raw_error_msg}{frame_summary}"
|
|
373
|
+
|
|
374
|
+
trace_store.update_trace_status(
|
|
375
|
+
trace_id, "failed", error=full_error_desc, device_serial=target_serial
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
device_info_line = f"Device Serial: `{target_serial}`\n" if target_serial else ""
|
|
379
|
+
failure_msg = (
|
|
380
|
+
f"Artemis background task failed.\n\n"
|
|
381
|
+
f"Trace ID: {trace_id}\n"
|
|
382
|
+
f"{device_info_line}"
|
|
383
|
+
f"Goal: {task_desc}\n"
|
|
384
|
+
f"Error: {full_error_desc}\n\n"
|
|
385
|
+
f'Check the logs using mobile_inspect_trace(action="view_summary", trace_id="{trace_id}") '
|
|
386
|
+
f"or inspect stderr log: [stderr.log](file://{stderr_log_path})."
|
|
387
|
+
)
|
|
388
|
+
notify(
|
|
389
|
+
conversation_id=conversation_id,
|
|
390
|
+
message=failure_msg,
|
|
391
|
+
title="Artemis Task Failed",
|
|
392
|
+
event_type="failed",
|
|
393
|
+
payload={
|
|
394
|
+
"trace_id": trace_id,
|
|
395
|
+
"device_serial": target_serial,
|
|
396
|
+
"goal": task_desc,
|
|
397
|
+
"error": full_error_desc,
|
|
398
|
+
},
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
finally:
|
|
402
|
+
print("Cleaning up resources...")
|
|
403
|
+
if agent:
|
|
404
|
+
try:
|
|
405
|
+
await agent.clean()
|
|
406
|
+
except Exception as e:
|
|
407
|
+
print(f"Error cleaning agent: {e}", file=sys.stderr)
|
|
408
|
+
|
|
409
|
+
sys.stdout = original_stdout
|
|
410
|
+
sys.stderr = original_stderr
|
|
411
|
+
log_file_out.close()
|
|
412
|
+
log_file_err.close()
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
if __name__ == "__main__":
|
|
416
|
+
parser = argparse.ArgumentParser(description="Artemis Background Task Runner")
|
|
417
|
+
parser.add_argument("--trace-id", required=True, help="Unique trace identifier")
|
|
418
|
+
parser.add_argument("--task-desc", required=True, help="Description of the task to run")
|
|
419
|
+
parser.add_argument("--model", required=True, help="Model to use ('Flash' or 'Pro')")
|
|
420
|
+
parser.add_argument(
|
|
421
|
+
"--conversation-id",
|
|
422
|
+
default="",
|
|
423
|
+
help="Conversation ID for wakeup notification routing (optional; empty disables routing)",
|
|
424
|
+
)
|
|
425
|
+
parser.add_argument("--locked-app-package", help="Package name of app to lock execution to")
|
|
426
|
+
parser.add_argument("--app-path", help="Path to local APK to install before running task")
|
|
427
|
+
parser.add_argument("--expected-output-desc", help="Expected output description")
|
|
428
|
+
parser.add_argument("--device-serial", help="Target specific device serial")
|
|
429
|
+
parser.add_argument(
|
|
430
|
+
"--verification-level",
|
|
431
|
+
help="Pro-profile Checker preset: 'off', 'final', 'checkpoints' or 'strict'",
|
|
432
|
+
)
|
|
433
|
+
parser.add_argument(
|
|
434
|
+
"--explorer-pro-mode",
|
|
435
|
+
help="Pro-profile Explorer perception version: 'flash', 'pro' or 'ultra'",
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
args = parser.parse_args()
|
|
439
|
+
|
|
440
|
+
asyncio.run(
|
|
441
|
+
run_task(
|
|
442
|
+
trace_id=args.trace_id,
|
|
443
|
+
task_desc=args.task_desc,
|
|
444
|
+
model=args.model,
|
|
445
|
+
conversation_id=args.conversation_id,
|
|
446
|
+
locked_app_package=args.locked_app_package,
|
|
447
|
+
app_path=args.app_path,
|
|
448
|
+
expected_output_desc=args.expected_output_desc,
|
|
449
|
+
device_serial=args.device_serial,
|
|
450
|
+
verification_level=args.verification_level,
|
|
451
|
+
explorer_pro_mode=args.explorer_pro_mode,
|
|
452
|
+
)
|
|
453
|
+
)
|