android-midscene-automation 0.2.4 → 1.1.1

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.
Files changed (525) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +159 -29
  3. package/artemis-main/.dockerignore +15 -0
  4. package/artemis-main/.env.example +34 -0
  5. package/artemis-main/CONTRIBUTING.md +35 -0
  6. package/artemis-main/Dockerfile +68 -0
  7. package/artemis-main/LICENSE +202 -0
  8. package/artemis-main/Makefile +115 -0
  9. package/artemis-main/README.md +322 -0
  10. package/artemis-main/README_CN.md +320 -0
  11. package/artemis-main/apps/__init__.py +15 -0
  12. package/artemis-main/apps/admin_console/__init__.py +19 -0
  13. package/artemis-main/apps/admin_console/core/__init__.py +13 -0
  14. package/artemis-main/apps/admin_console/core/config.py +43 -0
  15. package/artemis-main/apps/admin_console/core/security.py +178 -0
  16. package/artemis-main/apps/admin_console/core/state.py +243 -0
  17. package/artemis-main/apps/admin_console/database/__init__.py +13 -0
  18. package/artemis-main/apps/admin_console/database/connection.py +60 -0
  19. package/artemis-main/apps/admin_console/database/repositories/__init__.py +13 -0
  20. package/artemis-main/apps/admin_console/database/repositories/session_repository.py +564 -0
  21. package/artemis-main/apps/admin_console/database/repositories/step_repository.py +512 -0
  22. package/artemis-main/apps/admin_console/database/repositories/trace_repository.py +133 -0
  23. package/artemis-main/apps/admin_console/index.html +3787 -0
  24. package/artemis-main/apps/admin_console/replay_manager.py +2585 -0
  25. package/artemis-main/apps/admin_console/routers/__init__.py +13 -0
  26. package/artemis-main/apps/admin_console/routers/media.py +198 -0
  27. package/artemis-main/apps/admin_console/routers/replay.py +91 -0
  28. package/artemis-main/apps/admin_console/routers/sessions.py +239 -0
  29. package/artemis-main/apps/admin_console/routers/steps.py +109 -0
  30. package/artemis-main/apps/admin_console/routers/stream.py +56 -0
  31. package/artemis-main/apps/admin_console/routers/system.py +761 -0
  32. package/artemis-main/apps/admin_console/routers/tasks.py +517 -0
  33. package/artemis-main/apps/admin_console/schemas/__init__.py +13 -0
  34. package/artemis-main/apps/admin_console/schemas/task_schema.py +47 -0
  35. package/artemis-main/apps/admin_console/server.py +508 -0
  36. package/artemis-main/apps/admin_console/services/__init__.py +13 -0
  37. package/artemis-main/apps/admin_console/services/device_stream_service.py +137 -0
  38. package/artemis-main/apps/admin_console/services/ipc_service.py +262 -0
  39. package/artemis-main/apps/admin_console/services/media_service.py +623 -0
  40. package/artemis-main/apps/admin_console/services/model_service.py +148 -0
  41. package/artemis-main/apps/admin_console/services/task_preset_catalog.py +514 -0
  42. package/artemis-main/apps/admin_console/services/task_queue_service.py +1719 -0
  43. package/artemis-main/apps/admin_console/services/worker_process_io.py +144 -0
  44. package/artemis-main/apps/showcase_ui/README.md +31 -0
  45. package/artemis-main/apps/showcase_ui/angular.json +132 -0
  46. package/artemis-main/apps/showcase_ui/package-lock.json +9472 -0
  47. package/artemis-main/apps/showcase_ui/package.json +39 -0
  48. package/artemis-main/apps/showcase_ui/proxy.conf.json +23 -0
  49. package/artemis-main/apps/showcase_ui/public/favicon.ico +0 -0
  50. package/artemis-main/apps/showcase_ui/public/logo.png +0 -0
  51. package/artemis-main/apps/showcase_ui/public/logo.svg +56 -0
  52. package/artemis-main/apps/showcase_ui/src/app/app.component.html +24 -0
  53. package/artemis-main/apps/showcase_ui/src/app/app.component.scss +49 -0
  54. package/artemis-main/apps/showcase_ui/src/app/app.component.spec.ts +42 -0
  55. package/artemis-main/apps/showcase_ui/src/app/app.component.ts +32 -0
  56. package/artemis-main/apps/showcase_ui/src/app/app.config.ts +29 -0
  57. package/artemis-main/apps/showcase_ui/src/app/app.routes.ts +27 -0
  58. package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream-startup.spec.ts +108 -0
  59. package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html +1436 -0
  60. package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.scss +3973 -0
  61. package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.ts +2235 -0
  62. package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.html +380 -0
  63. package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.scss +1171 -0
  64. package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.ts +270 -0
  65. package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.html +433 -0
  66. package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.scss +987 -0
  67. package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.ts +632 -0
  68. package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.html +130 -0
  69. package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.scss +406 -0
  70. package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.ts +74 -0
  71. package/artemis-main/apps/showcase_ui/src/app/components/nav-switcher/nav-switcher.component.scss +115 -0
  72. package/artemis-main/apps/showcase_ui/src/app/components/nav-switcher/nav-switcher.component.ts +52 -0
  73. package/artemis-main/apps/showcase_ui/src/app/core/data/smart-tasks.data.ts +334 -0
  74. package/artemis-main/apps/showcase_ui/src/app/core/i18n/language.service.spec.ts +55 -0
  75. package/artemis-main/apps/showcase_ui/src/app/core/i18n/language.service.ts +61 -0
  76. package/artemis-main/apps/showcase_ui/src/app/core/i18n/translate.pipe.ts +11 -0
  77. package/artemis-main/apps/showcase_ui/src/app/core/i18n/zh-cn.ts +651 -0
  78. package/artemis-main/apps/showcase_ui/src/app/core/models/markdown.model.ts +43 -0
  79. package/artemis-main/apps/showcase_ui/src/app/core/models/pro-tuning.model.spec.ts +47 -0
  80. package/artemis-main/apps/showcase_ui/src/app/core/models/pro-tuning.model.ts +165 -0
  81. package/artemis-main/apps/showcase_ui/src/app/core/models/session.model.ts +85 -0
  82. package/artemis-main/apps/showcase_ui/src/app/core/models/stream.model.ts +246 -0
  83. package/artemis-main/apps/showcase_ui/src/app/core/models/system.model.ts +118 -0
  84. package/artemis-main/apps/showcase_ui/src/app/core/services/task-recommendation.service.ts +111 -0
  85. package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.html +2130 -0
  86. package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.scss +5204 -0
  87. package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.ts +1189 -0
  88. package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.html +39 -0
  89. package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.scss +151 -0
  90. package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.ts +58 -0
  91. package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.html +201 -0
  92. package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.scss +886 -0
  93. package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.ts +324 -0
  94. package/artemis-main/apps/showcase_ui/src/app/services/agent.service.spec.ts +418 -0
  95. package/artemis-main/apps/showcase_ui/src/app/services/agent.service.ts +2012 -0
  96. package/artemis-main/apps/showcase_ui/src/app/services/system.service.spec.ts +173 -0
  97. package/artemis-main/apps/showcase_ui/src/app/services/system.service.ts +620 -0
  98. package/artemis-main/apps/showcase_ui/src/app/utils/action-formatter.util.spec.ts +513 -0
  99. package/artemis-main/apps/showcase_ui/src/app/utils/action-formatter.util.ts +1015 -0
  100. package/artemis-main/apps/showcase_ui/src/app/utils/image-overlay.util.spec.ts +85 -0
  101. package/artemis-main/apps/showcase_ui/src/app/utils/image-overlay.util.ts +662 -0
  102. package/artemis-main/apps/showcase_ui/src/app/utils/markdown-parser.util.spec.ts +70 -0
  103. package/artemis-main/apps/showcase_ui/src/app/utils/markdown-parser.util.ts +383 -0
  104. package/artemis-main/apps/showcase_ui/src/app/utils/recording-timeline.util.spec.ts +107 -0
  105. package/artemis-main/apps/showcase_ui/src/app/utils/recording-timeline.util.ts +123 -0
  106. package/artemis-main/apps/showcase_ui/src/app/utils/run-info.util.spec.ts +92 -0
  107. package/artemis-main/apps/showcase_ui/src/app/utils/run-info.util.ts +116 -0
  108. package/artemis-main/apps/showcase_ui/src/app/utils/stream-aggregator.util.spec.ts +640 -0
  109. package/artemis-main/apps/showcase_ui/src/app/utils/stream-aggregator.util.ts +1021 -0
  110. package/artemis-main/apps/showcase_ui/src/app/utils/tool-formatter.util.spec.ts +375 -0
  111. package/artemis-main/apps/showcase_ui/src/app/utils/tool-formatter.util.ts +1419 -0
  112. package/artemis-main/apps/showcase_ui/src/index.html +37 -0
  113. package/artemis-main/apps/showcase_ui/src/main.ts +22 -0
  114. package/artemis-main/apps/showcase_ui/src/styles.scss +60 -0
  115. package/artemis-main/apps/showcase_ui/tsconfig.app.json +23 -0
  116. package/artemis-main/apps/showcase_ui/tsconfig.json +27 -0
  117. package/artemis-main/apps/showcase_ui/tsconfig.spec.json +23 -0
  118. package/artemis-main/artemis/__init__.py +44 -0
  119. package/artemis-main/artemis/__main__.py +18 -0
  120. package/artemis-main/artemis/_legacy_imports.py +94 -0
  121. package/artemis-main/artemis/_version.py +30 -0
  122. package/artemis-main/artemis/agents/__init__.py +17 -0
  123. package/artemis-main/artemis/agents/checker/checker.json +9 -0
  124. package/artemis-main/artemis/agents/checker/checker.py +859 -0
  125. package/artemis-main/artemis/agents/diagnoser/diagnoser.json +23 -0
  126. package/artemis-main/artemis/agents/diagnoser/diagnoser.py +608 -0
  127. package/artemis-main/artemis/agents/explorer/constants.py +52 -0
  128. package/artemis-main/artemis/agents/explorer/explorer.json +57 -0
  129. package/artemis-main/artemis/agents/explorer/explorer.py +473 -0
  130. package/artemis-main/artemis/agents/explorer/geometry.py +73 -0
  131. package/artemis-main/artemis/agents/explorer/native_runner.py +878 -0
  132. package/artemis-main/artemis/agents/explorer/perception_tools.py +632 -0
  133. package/artemis-main/artemis/agents/explorer/run_setup.py +403 -0
  134. package/artemis-main/artemis/agents/explorer/screen_index.py +266 -0
  135. package/artemis-main/artemis/agents/explorer/tiers.py +110 -0
  136. package/artemis-main/artemis/agents/explorer/tool_declarations.py +394 -0
  137. package/artemis-main/artemis/agents/explorer/universal_runner.py +317 -0
  138. package/artemis-main/artemis/agents/flash/context_compressor.py +452 -0
  139. package/artemis-main/artemis/agents/flash/flash_runner.md +51 -0
  140. package/artemis-main/artemis/agents/flash/flash_summarizer.md +53 -0
  141. package/artemis-main/artemis/agents/flash/flash_summarizer_single.md +54 -0
  142. package/artemis-main/artemis/agents/flash/runner.py +1167 -0
  143. package/artemis-main/artemis/agents/flash/summarizer.py +511 -0
  144. package/artemis-main/artemis/agents/history_analyzer/history_analyzer.md +8 -0
  145. package/artemis-main/artemis/agents/history_analyzer/history_analyzer.py +182 -0
  146. package/artemis-main/artemis/agents/image_processor/image_processor.md +74 -0
  147. package/artemis-main/artemis/agents/image_processor/image_processor.py +322 -0
  148. package/artemis-main/artemis/agents/log_analyzer/log_analyzer.md +15 -0
  149. package/artemis-main/artemis/agents/log_analyzer/log_analyzer.py +403 -0
  150. package/artemis-main/artemis/agents/log_analyzer/log_reader_sub_agent.md +8 -0
  151. package/artemis-main/artemis/agents/log_analyzer/output_analyzer.md +11 -0
  152. package/artemis-main/artemis/agents/log_analyzer/output_analyzer.py +163 -0
  153. package/artemis-main/artemis/agents/object_detector/object_detector.json +9 -0
  154. package/artemis-main/artemis/agents/object_detector/object_detector.py +211 -0
  155. package/artemis-main/artemis/agents/operator/operator.json +3 -0
  156. package/artemis-main/artemis/agents/operator/operator.py +1394 -0
  157. package/artemis-main/artemis/agents/operator/prompts.py +1064 -0
  158. package/artemis-main/artemis/agents/outputter/outputter.md +36 -0
  159. package/artemis-main/artemis/agents/outputter/outputter.py +552 -0
  160. package/artemis-main/artemis/agents/planner/planner.json +32 -0
  161. package/artemis-main/artemis/agents/planner/planner.py +436 -0
  162. package/artemis-main/artemis/agents/prompt_assembly.py +79 -0
  163. package/artemis-main/artemis/agents/summarizer/summarizer.py +190 -0
  164. package/artemis-main/artemis/agents/validator/action_execution.py +98 -0
  165. package/artemis-main/artemis/agents/validator/categories.py +33 -0
  166. package/artemis-main/artemis/agents/validator/execution_loop.py +488 -0
  167. package/artemis-main/artemis/agents/validator/incidents.py +120 -0
  168. package/artemis-main/artemis/agents/validator/pixel_safety_net.md +15 -0
  169. package/artemis-main/artemis/agents/validator/precondition_pixel.py +320 -0
  170. package/artemis-main/artemis/agents/validator/precondition_xml.py +672 -0
  171. package/artemis-main/artemis/agents/validator/tool_declarations.py +332 -0
  172. package/artemis-main/artemis/agents/validator/validator.py +188 -0
  173. package/artemis-main/artemis/agents/video_analyzer/__init__.py +15 -0
  174. package/artemis-main/artemis/agents/video_analyzer/audio_native.py +543 -0
  175. package/artemis-main/artemis/agents/video_analyzer/blackboard.py +821 -0
  176. package/artemis-main/artemis/agents/video_analyzer/chunk_agentic.py +455 -0
  177. package/artemis-main/artemis/agents/video_analyzer/chunk_conversation.py +491 -0
  178. package/artemis-main/artemis/agents/video_analyzer/chunk_native.py +437 -0
  179. package/artemis-main/artemis/agents/video_analyzer/conflict_resolution.py +137 -0
  180. package/artemis-main/artemis/agents/video_analyzer/gemini_files.py +162 -0
  181. package/artemis-main/artemis/agents/video_analyzer/native_coordinator.py +541 -0
  182. package/artemis-main/artemis/agents/video_analyzer/reliability.py +128 -0
  183. package/artemis-main/artemis/agents/video_analyzer/universal_engine.py +487 -0
  184. package/artemis-main/artemis/agents/video_analyzer/universal_tools.py +323 -0
  185. package/artemis-main/artemis/agents/video_analyzer/video_analyzer.md +51 -0
  186. package/artemis-main/artemis/agents/video_analyzer/video_analyzer.py +875 -0
  187. package/artemis-main/artemis/agents/video_analyzer/video_sub_agent.md +15 -0
  188. package/artemis-main/artemis/agents/video_analyzer/video_sub_agent_audio.md +12 -0
  189. package/artemis-main/artemis/clients/accessibility_client.py +438 -0
  190. package/artemis-main/artemis/clients/screen_client_factory.py +403 -0
  191. package/artemis-main/artemis/config/__init__.py +309 -0
  192. package/artemis-main/artemis/config/agent.py +1098 -0
  193. package/artemis-main/artemis/config/constants.py +151 -0
  194. package/artemis-main/artemis/config/core/__init__.py +24 -0
  195. package/artemis-main/artemis/config/core/engine.py +118 -0
  196. package/artemis-main/artemis/config/core/interpolator.py +78 -0
  197. package/artemis-main/artemis/config/llm.py +267 -0
  198. package/artemis-main/artemis/config/paths.py +244 -0
  199. package/artemis-main/artemis/config/runtime.py +197 -0
  200. package/artemis-main/artemis/config/settings.py +315 -0
  201. package/artemis-main/artemis/constants.py +47 -0
  202. package/artemis-main/artemis/context.py +289 -0
  203. package/artemis-main/artemis/controllers/__init__.py +41 -0
  204. package/artemis-main/artemis/controllers/controller_factory.py +41 -0
  205. package/artemis-main/artemis/controllers/device_controller.py +29 -0
  206. package/artemis-main/artemis/controllers/types.py +37 -0
  207. package/artemis-main/artemis/controllers/unified_controller.py +649 -0
  208. package/artemis-main/artemis/core/__init__.py +21 -0
  209. package/artemis-main/artemis/core/diagnostics/__init__.py +90 -0
  210. package/artemis-main/artemis/core/diagnostics/adb_keys.py +270 -0
  211. package/artemis-main/artemis/core/diagnostics/adb_server_connection.py +330 -0
  212. package/artemis-main/artemis/core/diagnostics/device_smoke.py +364 -0
  213. package/artemis-main/artemis/core/diagnostics/emulator_manager.py +501 -0
  214. package/artemis-main/artemis/core/diagnostics/engine.py +438 -0
  215. package/artemis-main/artemis/core/diagnostics/hierarchy_parity.py +216 -0
  216. package/artemis-main/artemis/core/diagnostics/probes/adb_probe.py +887 -0
  217. package/artemis-main/artemis/core/diagnostics/probes/base.py +45 -0
  218. package/artemis-main/artemis/core/diagnostics/probes/credentials_probe.py +296 -0
  219. package/artemis-main/artemis/core/diagnostics/probes/host_probe.py +427 -0
  220. package/artemis-main/artemis/core/diagnostics/probes/runtime_probe.py +169 -0
  221. package/artemis-main/artemis/core/diagnostics/probes/toolchain_probe.py +139 -0
  222. package/artemis-main/artemis/core/diagnostics/readiness.py +83 -0
  223. package/artemis-main/artemis/core/diagnostics/schema.py +118 -0
  224. package/artemis-main/artemis/core/tool_declaration.py +43 -0
  225. package/artemis-main/artemis/core/tool_failure.py +56 -0
  226. package/artemis-main/artemis/data_engine/context_vars.py +24 -0
  227. package/artemis-main/artemis/data_engine/engine.py +1615 -0
  228. package/artemis-main/artemis/data_engine/history_reader.py +142 -0
  229. package/artemis-main/artemis/data_engine/models.py +131 -0
  230. package/artemis-main/artemis/data_engine/storage.py +1245 -0
  231. package/artemis-main/artemis/data_engine/trace.py +727 -0
  232. package/artemis-main/artemis/drivers/__init__.py +48 -0
  233. package/artemis-main/artemis/drivers/android/adb_driver.py +507 -0
  234. package/artemis-main/artemis/drivers/android/hierarchy.py +64 -0
  235. package/artemis-main/artemis/drivers/android/input_ime.py +120 -0
  236. package/artemis-main/artemis/drivers/android/recorder.py +57 -0
  237. package/artemis-main/artemis/drivers/base.py +290 -0
  238. package/artemis-main/artemis/drivers/cloud/cloud_driver.py +117 -0
  239. package/artemis-main/artemis/drivers/factory.py +80 -0
  240. package/artemis-main/artemis/drivers/mock/mock_driver.py +198 -0
  241. package/artemis-main/artemis/drivers/types.py +67 -0
  242. package/artemis-main/artemis/graph/checkpoints.py +1243 -0
  243. package/artemis-main/artemis/graph/graph.py +1055 -0
  244. package/artemis-main/artemis/graph/perception.py +234 -0
  245. package/artemis-main/artemis/graph/state.py +151 -0
  246. package/artemis-main/artemis/graph/visibility.py +238 -0
  247. package/artemis-main/artemis/interfaces/cli/__init__.py +19 -0
  248. package/artemis-main/artemis/interfaces/cli/commands/__init__.py +15 -0
  249. package/artemis-main/artemis/interfaces/cli/commands/batch.py +278 -0
  250. package/artemis-main/artemis/interfaces/cli/commands/doctor.py +468 -0
  251. package/artemis-main/artemis/interfaces/cli/commands/helper.py +226 -0
  252. package/artemis-main/artemis/interfaces/cli/commands/init.py +193 -0
  253. package/artemis-main/artemis/interfaces/cli/commands/mcp.py +862 -0
  254. package/artemis-main/artemis/interfaces/cli/commands/run.py +463 -0
  255. package/artemis-main/artemis/interfaces/cli/commands/server.py +151 -0
  256. package/artemis-main/artemis/interfaces/cli/commands/server_lifecycle.py +328 -0
  257. package/artemis-main/artemis/interfaces/cli/commands/trace.py +111 -0
  258. package/artemis-main/artemis/interfaces/cli/commands/ui.py +404 -0
  259. package/artemis-main/artemis/interfaces/cli/main.py +109 -0
  260. package/artemis-main/artemis/interfaces/sdk/__init__.py +31 -0
  261. package/artemis-main/artemis/interfaces/sdk/client.py +19 -0
  262. package/artemis-main/artemis/interfaces/sdk/task.py +72 -0
  263. package/artemis-main/artemis/llm/__init__.py +25 -0
  264. package/artemis-main/artemis/llm/fake_model.py +179 -0
  265. package/artemis-main/artemis/llm/google/__init__.py +57 -0
  266. package/artemis-main/artemis/llm/google/provider.py +185 -0
  267. package/artemis-main/artemis/llm/google/usage.py +148 -0
  268. package/artemis-main/artemis/llm/parser.py +32 -0
  269. package/artemis-main/artemis/llm/reliability.py +267 -0
  270. package/artemis-main/artemis/llm/router.py +389 -0
  271. package/artemis-main/artemis/llm/schemas.py +36 -0
  272. package/artemis-main/artemis/llm/structured.py +196 -0
  273. package/artemis-main/artemis/main.py +58 -0
  274. package/artemis-main/artemis/mcp/__init__.py +20 -0
  275. package/artemis-main/artemis/mcp/action_executor.py +760 -0
  276. package/artemis-main/artemis/mcp/action_manifest.py +320 -0
  277. package/artemis-main/artemis/mcp/action_names.py +172 -0
  278. package/artemis-main/artemis/mcp/action_server.py +202 -0
  279. package/artemis-main/artemis/mcp/action_session.py +245 -0
  280. package/artemis-main/artemis/mcp/action_specs.py +868 -0
  281. package/artemis-main/artemis/mcp/action_types.py +86 -0
  282. package/artemis-main/artemis/mcp/actuators/__init__.py +21 -0
  283. package/artemis-main/artemis/mcp/actuators/adb.py +414 -0
  284. package/artemis-main/artemis/mcp/actuators/base.py +113 -0
  285. package/artemis-main/artemis/mcp/actuators/mock.py +70 -0
  286. package/artemis-main/artemis/mcp/adb_server.py +490 -0
  287. package/artemis-main/artemis/mcp/observation.py +133 -0
  288. package/artemis-main/artemis/mcp/xml_search_server.py +297 -0
  289. package/artemis-main/artemis/memory/__init__.py +90 -0
  290. package/artemis-main/artemis/memory/chunking.py +1843 -0
  291. package/artemis-main/artemis/memory/context_policy.py +226 -0
  292. package/artemis-main/artemis/memory/step_capsule.md +73 -0
  293. package/artemis-main/artemis/memory/step_memory.py +281 -0
  294. package/artemis-main/artemis/memory/transcript.py +798 -0
  295. package/artemis-main/artemis/platform/__init__.py +61 -0
  296. package/artemis-main/artemis/platform/base.py +104 -0
  297. package/artemis-main/artemis/platform/darwin.py +184 -0
  298. package/artemis-main/artemis/platform/linux.py +207 -0
  299. package/artemis-main/artemis/platform/windows.py +193 -0
  300. package/artemis-main/artemis/resources/__init__.py +46 -0
  301. package/artemis-main/artemis/runtime/__init__.py +108 -0
  302. package/artemis-main/artemis/runtime/adb_endpoint.py +173 -0
  303. package/artemis-main/artemis/runtime/awake_lease.py +283 -0
  304. package/artemis-main/artemis/runtime/awake_service.py +343 -0
  305. package/artemis-main/artemis/runtime/cancel_requests.py +254 -0
  306. package/artemis-main/artemis/runtime/daemon_client.py +422 -0
  307. package/artemis-main/artemis/runtime/device_lock.py +1013 -0
  308. package/artemis-main/artemis/runtime/device_pool.py +478 -0
  309. package/artemis-main/artemis/runtime/helper_manager.py +1030 -0
  310. package/artemis-main/artemis/runtime/process_probe.py +98 -0
  311. package/artemis-main/artemis/runtime/server_lifecycle.py +435 -0
  312. package/artemis-main/artemis/runtime/supervisor.py +121 -0
  313. package/artemis-main/artemis/runtime/trace_store.py +375 -0
  314. package/artemis-main/artemis/sdk/__init__.py +26 -0
  315. package/artemis-main/artemis/sdk/agent.py +485 -0
  316. package/artemis-main/artemis/sdk/builders/__init__.py +29 -0
  317. package/artemis-main/artemis/sdk/builders/agent_config_builder.py +474 -0
  318. package/artemis-main/artemis/sdk/constants.py +15 -0
  319. package/artemis-main/artemis/sdk/run_outcome.py +58 -0
  320. package/artemis-main/artemis/sdk/types/__init__.py +61 -0
  321. package/artemis-main/artemis/sdk/types/agent.py +89 -0
  322. package/artemis-main/artemis/sdk/utils.py +28 -0
  323. package/artemis-main/artemis/services/llm.py +1040 -0
  324. package/artemis-main/artemis/services/token_meter.py +267 -0
  325. package/artemis-main/artemis/telemetry/__init__.py +35 -0
  326. package/artemis-main/artemis/telemetry/models.py +64 -0
  327. package/artemis-main/artemis/telemetry/replay.py +34 -0
  328. package/artemis-main/artemis/telemetry/storage/json_storage.py +47 -0
  329. package/artemis-main/artemis/telemetry/tracer.py +85 -0
  330. package/artemis-main/artemis/toolchain/__init__.py +52 -0
  331. package/artemis-main/artemis/toolchain/descriptors.py +92 -0
  332. package/artemis-main/artemis/toolchain/resolver.py +185 -0
  333. package/artemis-main/artemis/tools/base.py +232 -0
  334. package/artemis-main/artemis/tools/command_tool.py +1240 -0
  335. package/artemis-main/artemis/tools/committee_prompts.json +5 -0
  336. package/artemis-main/artemis/tools/committee_tool.py +422 -0
  337. package/artemis-main/artemis/tools/diagnoser_submit_answer_tool.py +87 -0
  338. package/artemis-main/artemis/tools/diagnostic_tool.py +120 -0
  339. package/artemis-main/artemis/tools/explorer_tool.py +581 -0
  340. package/artemis-main/artemis/tools/history/__init__.py +398 -0
  341. package/artemis-main/artemis/tools/history/replay.py +120 -0
  342. package/artemis-main/artemis/tools/history/screenshot.py +139 -0
  343. package/artemis-main/artemis/tools/history/search.py +563 -0
  344. package/artemis-main/artemis/tools/image_processor_tool.py +124 -0
  345. package/artemis-main/artemis/tools/index.py +47 -0
  346. package/artemis-main/artemis/tools/log_tool.py +108 -0
  347. package/artemis-main/artemis/tools/mobile/launch_app.py +132 -0
  348. package/artemis-main/artemis/tools/mobile/log_utils.py +138 -0
  349. package/artemis-main/artemis/tools/mobile/ocr.py +202 -0
  350. package/artemis-main/artemis/tools/mobile/read_hierarchy.py +108 -0
  351. package/artemis-main/artemis/tools/mobile/read_logs.py +116 -0
  352. package/artemis-main/artemis/tools/mobile/search_logs.py +260 -0
  353. package/artemis-main/artemis/tools/object_detection_tool.py +244 -0
  354. package/artemis-main/artemis/tools/scratchpad.py +819 -0
  355. package/artemis-main/artemis/tools/system/adb_shell.py +31 -0
  356. package/artemis-main/artemis/tools/tool_wrapper.py +270 -0
  357. package/artemis-main/artemis/tools/video_tool.py +261 -0
  358. package/artemis-main/artemis/tools/wait_tool.py +97 -0
  359. package/artemis-main/artemis/utils/app_launch_utils.py +207 -0
  360. package/artemis-main/artemis/utils/coordinates.py +606 -0
  361. package/artemis-main/artemis/utils/credentials_validator.py +201 -0
  362. package/artemis-main/artemis/utils/cv_canvas.py +189 -0
  363. package/artemis-main/artemis/utils/cython_compat.py +45 -0
  364. package/artemis-main/artemis/utils/element_hit_test.py +80 -0
  365. package/artemis-main/artemis/utils/image_diff.py +335 -0
  366. package/artemis-main/artemis/utils/image_hash.py +80 -0
  367. package/artemis-main/artemis/utils/notes.py +470 -0
  368. package/artemis-main/artemis/utils/ocr_api.py +105 -0
  369. package/artemis-main/artemis/utils/ocr_xml_fusion.py +318 -0
  370. package/artemis-main/artemis/utils/plan_grammar.py +513 -0
  371. package/artemis-main/artemis/utils/python_executor.py +213 -0
  372. package/artemis-main/artemis/utils/startup_progress.py +60 -0
  373. package/artemis-main/artemis/utils/task_tree.py +1174 -0
  374. package/artemis-main/artemis/utils/text.py +37 -0
  375. package/artemis-main/artemis/utils/ui_filter.py +651 -0
  376. package/artemis-main/artemis/utils/video.py +685 -0
  377. package/artemis-main/artemis/utils/visualization.py +802 -0
  378. package/artemis-main/config/artemis.example.jsonc +12 -0
  379. package/artemis-main/mcp_server/README.md +111 -0
  380. package/artemis-main/mcp_server/__init__.py +21 -0
  381. package/artemis-main/mcp_server/__main__.py +20 -0
  382. package/artemis-main/mcp_server/background/__init__.py +15 -0
  383. package/artemis-main/mcp_server/background/task_runner.py +453 -0
  384. package/artemis-main/mcp_server/base.py +49 -0
  385. package/artemis-main/mcp_server/notifiers/__init__.py +74 -0
  386. package/artemis-main/mcp_server/notifiers/agentapi.py +289 -0
  387. package/artemis-main/mcp_server/notifiers/base.py +45 -0
  388. package/artemis-main/mcp_server/notifiers/composite.py +87 -0
  389. package/artemis-main/mcp_server/notifiers/desktop.py +108 -0
  390. package/artemis-main/mcp_server/notifiers/file.py +69 -0
  391. package/artemis-main/mcp_server/notifiers/script.py +90 -0
  392. package/artemis-main/mcp_server/notifiers/webhook.py +87 -0
  393. package/artemis-main/mcp_server/rules.md +68 -0
  394. package/artemis-main/mcp_server/server.py +106 -0
  395. package/artemis-main/mcp_server/tools/__init__.py +29 -0
  396. package/artemis-main/mcp_server/tools/device_state.py +107 -0
  397. package/artemis-main/mcp_server/tools/diagnose.py +1249 -0
  398. package/artemis-main/mcp_server/tools/inspect_trace.py +394 -0
  399. package/artemis-main/mcp_server/tools/task_manager.py +627 -0
  400. package/artemis-main/mcp_server/tools/task_runner.py +548 -0
  401. package/artemis-main/mcp_server/utils/__init__.py +15 -0
  402. package/artemis-main/mcp_server/utils/device_utils.py +180 -0
  403. package/artemis-main/mcp_server/utils/env_utils.py +65 -0
  404. package/artemis-main/packages/artemis-accessibility-helper/ArtemisAccessibilityHelper.apk +0 -0
  405. package/artemis-main/packages/artemis-accessibility-helper/app/build.gradle.kts +35 -0
  406. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/AndroidManifest.xml +49 -0
  407. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/A11yNode.java +274 -0
  408. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/ArtemisAccessibilityService.java +227 -0
  409. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/CommandServer.java +463 -0
  410. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/DisplayUtils.java +111 -0
  411. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/GestureController.java +232 -0
  412. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/HierarchyDumper.java +832 -0
  413. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/TokenReceiver.java +36 -0
  414. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/TokenStore.java +38 -0
  415. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/XmlUtils.java +102 -0
  416. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/res/values/strings.xml +4 -0
  417. package/artemis-main/packages/artemis-accessibility-helper/app/src/main/res/xml/accessibility_service_config.xml +10 -0
  418. package/artemis-main/packages/artemis-accessibility-helper/build.gradle.kts +3 -0
  419. package/artemis-main/packages/artemis-accessibility-helper/build_apk.sh +215 -0
  420. package/artemis-main/packages/artemis-accessibility-helper/debug.keystore +0 -0
  421. package/artemis-main/packages/artemis-accessibility-helper/gradle.properties +2 -0
  422. package/artemis-main/packages/artemis-accessibility-helper/helper_manifest.json +7 -0
  423. package/artemis-main/packages/artemis-accessibility-helper/settings.gradle.kts +17 -0
  424. package/artemis-main/packages/artemis-client/DESIGN.md +89 -0
  425. package/artemis-main/packages/artemis-client/README.md +112 -0
  426. package/artemis-main/packages/artemis-client/examples/basic.py +30 -0
  427. package/artemis-main/packages/artemis-client/pyproject.toml +36 -0
  428. package/artemis-main/packages/artemis-client/src/artemis_client/__init__.py +45 -0
  429. package/artemis-main/packages/artemis-client/src/artemis_client/client.py +401 -0
  430. package/artemis-main/packages/artemis-client/src/artemis_client/errors.py +66 -0
  431. package/artemis-main/packages/artemis-client/src/artemis_client/models.py +212 -0
  432. package/artemis-main/packages/artemis-client/src/artemis_client/py.typed +1 -0
  433. package/artemis-main/packages/artemis-client/src/artemis_client/transport.py +134 -0
  434. package/artemis-main/packages/artemis-client/tests/test_client.py +289 -0
  435. package/artemis-main/packages/artemis-client/tests/test_transport.py +85 -0
  436. package/artemis-main/pyproject.toml +259 -0
  437. package/artemis-main/pyright-core.json +17 -0
  438. package/artemis-main/scripts/check_dependency_sources.py +68 -0
  439. package/artemis-main/scripts/install_deps.ps1 +520 -0
  440. package/artemis-main/scripts/install_deps.sh +533 -0
  441. package/artemis-main/scripts/quality_ratchet.py +97 -0
  442. package/artemis-main/scripts/real_device_video_acceptance.py +483 -0
  443. package/artemis-main/scripts/run_edge_case_part.py +327 -0
  444. package/artemis-main/scripts/run_ui.py +242 -0
  445. package/artemis-main/scripts/start.ps1 +500 -0
  446. package/artemis-main/scripts/test_all_edge_cases.py +269 -0
  447. package/artemis-main/scripts/verify_concurrency_and_devices.py +385 -0
  448. package/artemis-main/setup.py +164 -0
  449. package/artemis-main/start.bat +35 -0
  450. package/artemis-main/start.sh +423 -0
  451. package/artemis-main/third_party/mobile_use/LICENSE +190 -0
  452. package/artemis-main/third_party/mobile_use/METADATA +27 -0
  453. package/artemis-main/third_party/mobile_use/NOTICE +12 -0
  454. package/artemis-main/third_party/mobile_use/__init__.py +19 -0
  455. package/artemis-main/third_party/mobile_use/agents/__init__.py +13 -0
  456. package/artemis-main/third_party/mobile_use/agents/hopper/__init__.py +13 -0
  457. package/artemis-main/third_party/mobile_use/agents/hopper/hopper.md +22 -0
  458. package/artemis-main/third_party/mobile_use/agents/hopper/hopper.py +80 -0
  459. package/artemis-main/third_party/mobile_use/clients/__init__.py +13 -0
  460. package/artemis-main/third_party/mobile_use/clients/ui_automator_client.py +482 -0
  461. package/artemis-main/third_party/mobile_use/config/__init__.py +13 -0
  462. package/artemis-main/third_party/mobile_use/config/llm.py +183 -0
  463. package/artemis-main/third_party/mobile_use/config/output.py +184 -0
  464. package/artemis-main/third_party/mobile_use/context.py +119 -0
  465. package/artemis-main/third_party/mobile_use/controllers/__init__.py +13 -0
  466. package/artemis-main/third_party/mobile_use/controllers/platform_specific_commands_controller.py +151 -0
  467. package/artemis-main/third_party/mobile_use/controllers/types.py +92 -0
  468. package/artemis-main/third_party/mobile_use/controllers/unified_controller.py +183 -0
  469. package/artemis-main/third_party/mobile_use/graph.py +54 -0
  470. package/artemis-main/third_party/mobile_use/llm_service.py +193 -0
  471. package/artemis-main/third_party/mobile_use/main.py +130 -0
  472. package/artemis-main/third_party/mobile_use/sdk/__init__.py +13 -0
  473. package/artemis-main/third_party/mobile_use/sdk/agent.py +1060 -0
  474. package/artemis-main/third_party/mobile_use/sdk/builders/__init__.py +13 -0
  475. package/artemis-main/third_party/mobile_use/sdk/builders/agent_config_builder.py +225 -0
  476. package/artemis-main/third_party/mobile_use/sdk/builders/index.py +33 -0
  477. package/artemis-main/third_party/mobile_use/sdk/builders/task_request_builder.py +243 -0
  478. package/artemis-main/third_party/mobile_use/sdk/types/__init__.py +13 -0
  479. package/artemis-main/third_party/mobile_use/sdk/types/agent.py +98 -0
  480. package/artemis-main/third_party/mobile_use/sdk/types/exceptions.py +109 -0
  481. package/artemis-main/third_party/mobile_use/sdk/types/task.py +234 -0
  482. package/artemis-main/third_party/mobile_use/testing.py +59 -0
  483. package/artemis-main/third_party/mobile_use/tools/__init__.py +13 -0
  484. package/artemis-main/third_party/mobile_use/tools/index.py +44 -0
  485. package/artemis-main/third_party/mobile_use/tools/mobile/__init__.py +13 -0
  486. package/artemis-main/third_party/mobile_use/tools/mobile/launch_app.py +89 -0
  487. package/artemis-main/third_party/mobile_use/tools/tool_wrapper.py +52 -0
  488. package/artemis-main/third_party/mobile_use/utils/__init__.py +13 -0
  489. package/artemis-main/third_party/mobile_use/utils/app_launch_utils.py +217 -0
  490. package/artemis-main/third_party/mobile_use/utils/cli_helpers.py +60 -0
  491. package/artemis-main/third_party/mobile_use/utils/decorators.py +158 -0
  492. package/artemis-main/third_party/mobile_use/utils/file.py +31 -0
  493. package/artemis-main/third_party/mobile_use/utils/logger.py +216 -0
  494. package/artemis-main/third_party/mobile_use/utils/media.py +213 -0
  495. package/artemis-main/third_party/mobile_use/utils/shell_utils.py +39 -0
  496. package/artemis-main/third_party/mobile_use/utils/video.py +398 -0
  497. package/artemis-main/uv.lock +4908 -0
  498. package/bin/android-midscene-automation.js +1 -5
  499. package/bin/artemis-config.mjs +15 -0
  500. package/bin/artemis-embedded.py +56 -0
  501. package/bin/start-artemis.mjs +30 -0
  502. package/bin/start-dev.mjs +112 -0
  503. package/bin/test_artemis_embedded.py +44 -0
  504. package/package.json +4 -2
  505. package/server/artemis.ts +34 -0
  506. package/server/http-api.ts +12 -0
  507. package/src/App.vue +10 -5
  508. package/src/api.ts +5 -0
  509. package/src/appium-recorder/AppiumPage.vue +1 -1
  510. package/src/appium-recorder/components/ComponentInspector.vue +1 -1
  511. package/src/appium-recorder/components/FlowNodeSearch.vue +3 -3
  512. package/src/appium-recorder/components/ImageCheckDialog.vue +3 -3
  513. package/src/appium-recorder/components/RecorderWorkspace.vue +4 -4
  514. package/src/appium-recorder/flow-appearance.ts +4 -4
  515. package/src/components/AppSidebar.vue +8 -7
  516. package/src/components/MidsceneMaintenanceNotice.vue +17 -0
  517. package/src/components/analytics/AnalysisCharts.vue +4 -4
  518. package/src/components/analytics/ReportAnalysis.vue +1 -1
  519. package/src/components/generator/TestCaseFileUpload.vue +1 -1
  520. package/src/components/help/HelpCenter.vue +56 -37
  521. package/src/pages/AiGeneratorPage.vue +1 -1
  522. package/src/pages/ArtemisPage.vue +72 -0
  523. package/src/pages/ConfigPage.vue +18 -19
  524. package/src/style.css +340 -121
  525. package/src/types.ts +1 -1
@@ -0,0 +1,463 @@
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
+ """Task execution command (artemis run)."""
16
+
17
+ import asyncio
18
+ import os
19
+ from typing import Annotated
20
+
21
+ from langchain_core.callbacks.base import Callbacks
22
+ from artemis.config import checker_overrides_for_level, settings
23
+ from artemis.utils.startup_progress import publish_startup_progress
24
+ from third_party.mobile_use.main import (
25
+ GoalArgument,
26
+ OutputDescriptionOption,
27
+ TestNameOption,
28
+ TracesPathOption,
29
+ VideoRecordingToolsOption,
30
+ ensure_video_recording_available,
31
+ new_default_config_builder,
32
+ run_automation,
33
+ )
34
+ from third_party.mobile_use.utils.cli_helpers import display_local_device_status
35
+ from third_party.mobile_use.utils.logger import get_logger
36
+ import signal
37
+ from rich.console import Console
38
+ from rich.panel import Panel
39
+ import typer
40
+
41
+ logger = get_logger(__name__)
42
+
43
+
44
+ async def execute_task(
45
+ goal: str,
46
+ device_serial: str | None = None,
47
+ session_id: str | None = None,
48
+ locked_app_package: str | None = None,
49
+ test_name: str | None = None,
50
+ traces_output_path_str: str | None = None,
51
+ output_description: str | None = None,
52
+ graph_config_callbacks: Callbacks = [],
53
+ video_recording_tools_enabled: bool | None = None,
54
+ profile: str | None = None,
55
+ app_path: str | None = None,
56
+ enable_planner_validation: bool | None = None,
57
+ enable_committee: bool | None = None,
58
+ enable_checker: bool | None = None,
59
+ enable_step_summarizer: bool | None = None,
60
+ enable_outputter: bool | None = None,
61
+ force_output_synthesis: bool | None = None,
62
+ explorer_version: str | None = None,
63
+ explorer_flash_mode: str | None = None,
64
+ explorer_pro_mode: str | None = None,
65
+ verification_level: str | None = None,
66
+ ) -> None:
67
+ """Executes a single mobile automation task end-to-end.
68
+
69
+ Args:
70
+ goal: Target objective to achieve on the mobile device.
71
+ locked_app_package: Optional package name to constrain actions to.
72
+ test_name: Optional test identifier for trace directory naming.
73
+ traces_output_path_str: Destination path for recording traces.
74
+ output_description: Structured natural language output description.
75
+ graph_config_callbacks: LangGraph callback handlers.
76
+ video_recording_tools_enabled: Whether screen video analyzer is enabled.
77
+ profile: Execution profile ('flash' for fast reactive loop, 'pro' for full graph).
78
+ app_path: Optional local APK path to install prior to execution.
79
+ enable_planner_validation: Explicit override to enable/disable async planner validation.
80
+ enable_committee: Explicit override to enable/disable Multi-Agent Committee tool.
81
+ explorer_version: Override the fallback Explorer tier ('flash', 'pro', or 'ultra').
82
+ explorer_flash_mode: Override the Explorer tier for the Flash execution profile.
83
+ explorer_pro_mode: Override the Explorer tier for the Pro execution profile.
84
+ verification_level: Coarse Checker preset ('off', 'final', 'checkpoints',
85
+ 'strict'); applied before the explicit ``enable_checker`` switch.
86
+ """
87
+ effective_sid = (
88
+ session_id or os.getenv("ARTEMIS_SESSION_ID") or os.getenv("ARTEMIS_CLOUD_SESSION_ID")
89
+ )
90
+ if effective_sid:
91
+ os.environ["ARTEMIS_SESSION_ID"] = str(effective_sid)
92
+ if not os.environ.get("ARTEMIS_TASK_INGRESS"):
93
+ os.environ["ARTEMIS_TASK_INGRESS"] = "cli"
94
+ publish_startup_progress(
95
+ "configuration",
96
+ "Loading the run configuration",
97
+ session_id=str(effective_sid) if effective_sid else None,
98
+ )
99
+
100
+ config = new_default_config_builder()
101
+
102
+ if video_recording_tools_enabled is not None:
103
+ config.with_video_recording_tools(enabled=video_recording_tools_enabled)
104
+
105
+ if enable_planner_validation is not None:
106
+ config.with_planner_validation(enabled=enable_planner_validation)
107
+
108
+ if enable_committee is not None:
109
+ config.with_committee(enabled=enable_committee)
110
+
111
+ if verification_level is not None:
112
+ config.with_checker(**checker_overrides_for_level(verification_level))
113
+
114
+ if enable_checker is not None:
115
+ config.with_checker(enabled=enable_checker)
116
+
117
+ if enable_step_summarizer is not None:
118
+ config.with_flash_step_summarizer(enabled=enable_step_summarizer)
119
+
120
+ if enable_outputter is not None or force_output_synthesis is not None:
121
+ config.with_outputter(
122
+ enabled=enable_outputter if enable_outputter is not None else True,
123
+ force_synthesis=bool(force_output_synthesis),
124
+ )
125
+
126
+ if (
127
+ explorer_version is not None
128
+ or explorer_flash_mode is not None
129
+ or explorer_pro_mode is not None
130
+ ):
131
+ config.with_explorer(
132
+ version=explorer_version,
133
+ flash_mode=explorer_flash_mode,
134
+ pro_mode=explorer_pro_mode,
135
+ )
136
+
137
+ target_serial = (
138
+ device_serial or settings.ADB_DEVICE_SERIAL or os.environ.get("ADB_DEVICE_SERIAL")
139
+ )
140
+ if not target_serial:
141
+ try:
142
+ from artemis.runtime import device_pool
143
+
144
+ target_serial = device_pool.select_device()
145
+ except Exception:
146
+ target_serial = None
147
+
148
+ if target_serial:
149
+ from artemis.context import DevicePlatform
150
+
151
+ config.for_device(DevicePlatform.ANDROID, target_serial)
152
+
153
+ if graph_config_callbacks:
154
+ config.with_graph_config_callbacks(graph_config_callbacks)
155
+
156
+ await run_automation(
157
+ config,
158
+ goal,
159
+ session_id=effective_sid,
160
+ locked_app_package=locked_app_package,
161
+ test_name=test_name,
162
+ traces_output_path_str=traces_output_path_str,
163
+ output_description=output_description,
164
+ profile=profile,
165
+ app_path=app_path,
166
+ )
167
+
168
+
169
+ def run_command(
170
+ goal: GoalArgument,
171
+ profile: Annotated[
172
+ str | None,
173
+ typer.Option(
174
+ "--profile",
175
+ "-p",
176
+ help="Execution profile ('flash' for fast reactive, 'pro' for full graph).",
177
+ ),
178
+ ] = "pro",
179
+ locked_app_package: Annotated[
180
+ str | None,
181
+ typer.Option(
182
+ "--locked-app",
183
+ "-a",
184
+ help="Optional Android package name to restrict the agent to.",
185
+ ),
186
+ ] = None,
187
+ test_name: TestNameOption = None,
188
+ traces_path: TracesPathOption = None,
189
+ output_description: OutputDescriptionOption = None,
190
+ with_video_recording_tools: VideoRecordingToolsOption = None,
191
+ app_path: Annotated[
192
+ str | None,
193
+ typer.Option(
194
+ "--app-path",
195
+ help="Local APK path to install before starting the task.",
196
+ ),
197
+ ] = None,
198
+ enable_planner_validation: Annotated[
199
+ bool | None,
200
+ typer.Option(
201
+ "--enable-planner-validation/--disable-planner-validation",
202
+ help="Enable or disable the advisory Planner review of task plan milestone edits (hint only, never rolled back).",
203
+ ),
204
+ ] = None,
205
+ enable_committee: Annotated[
206
+ bool | None,
207
+ typer.Option(
208
+ "--enable-committee/--disable-committee",
209
+ help="Enable or disable Multi-Agent Committee council debate tool for Operator.",
210
+ ),
211
+ ] = None,
212
+ enable_checker: Annotated[
213
+ bool | None,
214
+ typer.Option(
215
+ "--enable-checker/--disable-checker",
216
+ help="Enable or disable the Checker (plan checkpoint verification and exit final review).",
217
+ ),
218
+ ] = None,
219
+ enable_step_summarizer: Annotated[
220
+ bool | None,
221
+ typer.Option(
222
+ "--enable-step-summarizer/--disable-step-summarizer",
223
+ help="Enable or disable Flash asynchronous objective visual step state summarizer.",
224
+ ),
225
+ ] = None,
226
+ enable_outputter: Annotated[
227
+ bool | None,
228
+ typer.Option(
229
+ "--enable-outputter/--disable-outputter",
230
+ help="Enable or disable Outputter post-execution report and structured output synthesis.",
231
+ ),
232
+ ] = None,
233
+ force_output_synthesis: Annotated[
234
+ bool | None,
235
+ typer.Option(
236
+ "--force-output-synthesis/--no-force-output-synthesis",
237
+ help="Force Outputter report synthesis even if no structured output schema is specified.",
238
+ ),
239
+ ] = None,
240
+ explorer_version: Annotated[
241
+ str | None,
242
+ typer.Option(
243
+ "--explorer-version",
244
+ help=(
245
+ "Fallback Explorer tier when no profile knob applies: 'flash' (one-shot"
246
+ " detection), 'pro' (3-turn reasoning loop) or 'ultra' (8-turn loop with"
247
+ " zoom, OCR and image processing)."
248
+ ),
249
+ ),
250
+ ] = None,
251
+ explorer_flash_mode: Annotated[
252
+ str | None,
253
+ typer.Option(
254
+ "--explorer-flash-mode",
255
+ help="Explorer tier behind ask_explorer under the Flash profile ('flash', 'pro', 'ultra').",
256
+ ),
257
+ ] = None,
258
+ explorer_pro_mode: Annotated[
259
+ str | None,
260
+ typer.Option(
261
+ "--explorer-pro-mode",
262
+ help="Explorer tier behind ask_explorer under the Pro profile ('flash', 'pro', 'ultra').",
263
+ ),
264
+ ] = None,
265
+ verification_level: Annotated[
266
+ str | None,
267
+ typer.Option(
268
+ "--verification-level",
269
+ help=(
270
+ "Checker preset for the Pro profile: 'off' (no audit), 'final' (exit review"
271
+ " only, the default), 'checkpoints' (every plan checkpoint + exit review),"
272
+ " 'strict' (checkpoints with a larger repair budget; a failed assert halts)."
273
+ ),
274
+ ),
275
+ ] = None,
276
+ device_serial: Annotated[
277
+ str | None,
278
+ typer.Option(
279
+ "--device-serial",
280
+ "-s",
281
+ help="Target specific Android device by serial number (e.g. emulator-5554).",
282
+ ),
283
+ ] = None,
284
+ session_id: Annotated[
285
+ str | None,
286
+ typer.Option(
287
+ "--session-id",
288
+ help="Canonical session UUID for trace and stream telemetry.",
289
+ ),
290
+ ] = None,
291
+ standalone: Annotated[
292
+ bool,
293
+ typer.Option(
294
+ "--standalone",
295
+ help="Run in standalone embedded mode without auto-spawning the Artemis Daemon.",
296
+ ),
297
+ ] = False,
298
+ ) -> None:
299
+ """Run an autonomous UI automation task on the connected Android device."""
300
+ ensure_video_recording_available(with_video_recording_tools)
301
+
302
+ console = Console()
303
+
304
+ is_worker = (
305
+ os.environ.get("ARTEMIS_TASK_WORKER") == "1"
306
+ or os.environ.get("ARTEMIS_DEVICE_QUEUE_TICKET") is not None
307
+ )
308
+ is_standalone = standalone or os.environ.get("ARTEMIS_STANDALONE") == "1"
309
+
310
+ # All platforms route through unified Artemis Daemon unless specifically configured as standalone
311
+ if not is_worker and not is_standalone:
312
+ try:
313
+ import uuid
314
+ from artemis.runtime import (
315
+ ensure_daemon_running,
316
+ submit_task_to_daemon,
317
+ wait_for_daemon_task,
318
+ stop_task_on_daemon,
319
+ )
320
+
321
+ console.print("[dim]Connecting to Artemis Daemon scheduler...[/dim]")
322
+ is_running, base_url = ensure_daemon_running(timeout=8.0, wait_ready=True)
323
+ if is_running and base_url:
324
+ target_sid = session_id or str(uuid.uuid4())
325
+ console.print(
326
+ f"[bold green]āœ“[/bold green] Artemis Daemon active at [cyan]{base_url}[/cyan]"
327
+ )
328
+ resp = submit_task_to_daemon(
329
+ goal=goal,
330
+ profile=profile or "pro",
331
+ device_serial=device_serial,
332
+ expected_output=output_description,
333
+ enable_outputter=enable_outputter,
334
+ locked_app_package=locked_app_package,
335
+ app_path=app_path,
336
+ session_id=target_sid,
337
+ ingress="cli",
338
+ base_url=base_url,
339
+ )
340
+ if resp and resp.get("tasks"):
341
+ console.print(
342
+ f"[bold green]āœ“[/bold green] Task scheduled in unified queue (Session: [cyan]{target_sid}[/cyan])"
343
+ )
344
+ console.print(f"[dim]Live dashboard & replay: {base_url}[/dim]\n")
345
+
346
+ def on_status(sess_info):
347
+ st = sess_info.get("status")
348
+ if st == "queued":
349
+ console.print(
350
+ "[yellow]ā³ Task queued in scheduler, waiting for device...[/yellow]"
351
+ )
352
+ elif st == "running":
353
+ console.print("[green]ā–¶ Task executing on mobile device...[/green]")
354
+
355
+ try:
356
+ final_res = wait_for_daemon_task(
357
+ target_sid,
358
+ base_url=base_url,
359
+ timeout=1800.0,
360
+ on_status_update=on_status,
361
+ )
362
+ final_st = final_res.get("status")
363
+ if final_st in ("completed", "success"):
364
+ console.print(
365
+ "\n[bold green]āœ… Task completed successfully![/bold green]"
366
+ )
367
+ return
368
+ else:
369
+ err = final_res.get("error") or final_res.get("explanation") or ""
370
+ console.print(f"\n[bold red]āœ– Task {final_st}[/bold red]: {err}")
371
+ raise SystemExit(1)
372
+ except KeyboardInterrupt:
373
+ console.print("\n[yellow]Stopping task on Daemon...[/yellow]")
374
+ stop_task_on_daemon(target_sid, base_url=base_url)
375
+ console.print("[yellow]Task cancelled.[/yellow]")
376
+ raise SystemExit(130)
377
+ else:
378
+ console.print(
379
+ "[yellow]Warning: Could not enqueue task to Daemon. Falling back to local execution...[/yellow]"
380
+ )
381
+ else:
382
+ console.print(
383
+ "[yellow]Warning: Artemis Daemon could not be started. Falling back to local execution...[/yellow]"
384
+ )
385
+ except SystemExit:
386
+ raise
387
+ except Exception as exc:
388
+ logger.debug(f"Daemon dispatch error: {exc}")
389
+ console.print(
390
+ f"[yellow]Daemon routing notice: {exc}. Falling back to local execution...[/yellow]"
391
+ )
392
+
393
+ display_local_device_status(console, host=settings.ADB_HOST, port=settings.ADB_PORT)
394
+
395
+ cancelled = False
396
+ original_sigterm = None
397
+ try:
398
+ if hasattr(signal, "SIGTERM"):
399
+ original_sigterm = signal.signal(
400
+ signal.SIGTERM, lambda s, f: (_ for _ in ()).throw(KeyboardInterrupt())
401
+ )
402
+ except (ValueError, OSError, RuntimeError):
403
+ # Not the main thread or platform does not support SIGTERM handlers;
404
+ # run proceeds without the graceful-cancel hook.
405
+ pass
406
+
407
+ try:
408
+ asyncio.run(
409
+ execute_task(
410
+ goal=goal,
411
+ device_serial=device_serial,
412
+ session_id=session_id,
413
+ locked_app_package=locked_app_package,
414
+ test_name=test_name,
415
+ traces_output_path_str=traces_path,
416
+ output_description=output_description,
417
+ video_recording_tools_enabled=with_video_recording_tools,
418
+ profile=profile,
419
+ app_path=app_path,
420
+ enable_planner_validation=enable_planner_validation,
421
+ enable_committee=enable_committee,
422
+ enable_checker=enable_checker,
423
+ enable_step_summarizer=enable_step_summarizer,
424
+ enable_outputter=enable_outputter,
425
+ force_output_synthesis=force_output_synthesis,
426
+ explorer_version=explorer_version,
427
+ explorer_flash_mode=explorer_flash_mode,
428
+ explorer_pro_mode=explorer_pro_mode,
429
+ verification_level=verification_level,
430
+ )
431
+ )
432
+ except (KeyboardInterrupt, asyncio.CancelledError):
433
+ # KeyboardInterrupt: Ctrl+C / SIGTERM. CancelledError: the daemon asked
434
+ # this worker to stop through a cancel marker and the Agent cancelled
435
+ # its own task so the recording and trace could be finalized.
436
+ cancelled = True
437
+ except Exception as e:
438
+ err_msg = str(e)
439
+ if "API_KEY" in err_msg or "requires" in err_msg:
440
+ console.print()
441
+ console.print(
442
+ Panel(
443
+ f"[bold red]āœ– Authentication Error:[/bold red] {err_msg}\n\n"
444
+ "šŸ’” [bold cyan]Quick Fix:[/bold cyan] Run [bold green]artemis init[/bold green] to configure your API key in 10 seconds,\n"
445
+ "or add [bold]GEMINI_API_KEY=your_key[/bold] to [dim].env[/dim].",
446
+ title="Missing API Key",
447
+ expand=False,
448
+ )
449
+ )
450
+ console.print()
451
+ raise SystemExit(1)
452
+ else:
453
+ console.print(f"[bold red]Task execution failed:[/bold red] {e}")
454
+ raise
455
+ finally:
456
+ try:
457
+ if original_sigterm is not None and hasattr(signal, "SIGTERM"):
458
+ signal.signal(signal.SIGTERM, original_sigterm)
459
+ except (ValueError, OSError, RuntimeError):
460
+ # Best-effort restore of the previous handler on the way out.
461
+ pass
462
+ if cancelled:
463
+ raise SystemExit(130)
@@ -0,0 +1,151 @@
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
+ """Server and cloud proxy commands (artemis server)."""
16
+
17
+ import http.server
18
+ import os
19
+ import socketserver
20
+ import subprocess
21
+ import time
22
+ from typing import Annotated
23
+ import urllib.error
24
+ import urllib.request
25
+
26
+ from artemis.interfaces.cli.commands.server_lifecycle import (
27
+ restart_command,
28
+ status_command,
29
+ stop_command,
30
+ )
31
+ from third_party.mobile_use.utils.logger import get_logger
32
+ import typer
33
+
34
+ logger = get_logger(__name__)
35
+ server_app = typer.Typer(help="Cloud proxy and server management commands.")
36
+
37
+ server_app.command("restart", help="Restart running Artemis Web UI & server.")(restart_command)
38
+ server_app.command("stop", help="Stop running Artemis Web UI & server.")(stop_command)
39
+ server_app.command("status", help="Display Artemis Web UI & server status.")(status_command)
40
+
41
+ cached_token = ""
42
+ token_expire_time = 0.0
43
+
44
+
45
+ def get_identity_token() -> str:
46
+ """Fetch Google Cloud IAM identity token for authenticated requests."""
47
+ global cached_token, token_expire_time
48
+ now = time.time()
49
+ if not cached_token or now >= token_expire_time:
50
+ try:
51
+ res = subprocess.check_output(
52
+ ["gcloud", "auth", "print-identity-token"], text=True
53
+ ).strip()
54
+ cached_token = res
55
+ token_expire_time = now + 1800 # cache 30 mins
56
+ except Exception as e:
57
+ logger.warning(f"Failed to get GCP identity token: {e}")
58
+ return ""
59
+ return cached_token
60
+
61
+
62
+ class CloudRunProxyHandler(http.server.BaseHTTPRequestHandler):
63
+ target_url: str = os.getenv("ARTEMIS_CLOUD_URL", "http://127.0.0.1:8000")
64
+
65
+ def log_message(self, format, *args):
66
+ logger.info(f"[{self.log_date_time_string()}] {format % args}")
67
+
68
+ def do_GET(self):
69
+ self.proxy_request("GET")
70
+
71
+ def do_POST(self):
72
+ self.proxy_request("POST")
73
+
74
+ def do_DELETE(self):
75
+ self.proxy_request("DELETE")
76
+
77
+ def do_OPTIONS(self):
78
+ self.send_response(200)
79
+ self.send_header("Access-Control-Allow-Origin", "*")
80
+ self.send_header("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS")
81
+ self.send_header("Access-Control-Allow-Headers", "*")
82
+ self.end_headers()
83
+
84
+ def proxy_request(self, method: str):
85
+ url = f"{self.target_url}{self.path}"
86
+ headers = {}
87
+ for k, v in self.headers.items():
88
+ if k.lower() not in ("host", "authorization", "content-length"):
89
+ headers[k] = v
90
+
91
+ token = get_identity_token()
92
+ if token:
93
+ headers["Authorization"] = f"Bearer {token}"
94
+ tenant_token = os.getenv("ARTEMIS_TENANT_TOKEN")
95
+ if tenant_token:
96
+ headers["X-Artemis-Token"] = tenant_token
97
+
98
+ content_length = int(self.headers.get("Content-Length", 0))
99
+ body = self.rfile.read(content_length) if content_length > 0 else None
100
+
101
+ req = urllib.request.Request(url, data=body, headers=headers, method=method)
102
+ try:
103
+ with urllib.request.urlopen(req, timeout=30) as resp:
104
+ self.send_response(resp.status)
105
+ for k, v in resp.getheaders():
106
+ if k.lower() not in ("transfer-encoding", "content-encoding", "content-length"):
107
+ self.send_header(k, v)
108
+ data = resp.read()
109
+ self.send_header("Content-Length", str(len(data)))
110
+ self.send_header("Access-Control-Allow-Origin", "*")
111
+ self.end_headers()
112
+ self.wfile.write(data)
113
+ except urllib.error.HTTPError as e:
114
+ self.send_response(e.code)
115
+ for k, v in e.headers.items():
116
+ if k.lower() not in ("transfer-encoding", "content-encoding", "content-length"):
117
+ self.send_header(k, v)
118
+ data = e.read()
119
+ self.send_header("Content-Length", str(len(data)))
120
+ self.send_header("Access-Control-Allow-Origin", "*")
121
+ self.end_headers()
122
+ self.wfile.write(data)
123
+ except Exception as e:
124
+ self.send_response(500)
125
+ self.end_headers()
126
+ self.wfile.write(f"Proxy Error: {e}".encode())
127
+
128
+
129
+ @server_app.command("web")
130
+ def web_proxy_command(
131
+ port: Annotated[int, typer.Option("--port", "-p", help="Local port to bind.")] = 8080,
132
+ target: Annotated[
133
+ str,
134
+ typer.Option(
135
+ "--target", "-t", help="Target Artemis Cloud URL.", envvar="ARTEMIS_CLOUD_URL"
136
+ ),
137
+ ] = "http://127.0.0.1:8000",
138
+ ) -> None:
139
+ """Start the local authenticated proxy for ARTEMIS Cloud Web Dashboard."""
140
+ CloudRunProxyHandler.target_url = target
141
+ typer.secho(
142
+ f"šŸš€ Starting Artemis Cloud Web Proxy at http://localhost:{port}", fg=typer.colors.GREEN
143
+ )
144
+ typer.secho(f"šŸ”— Forwarding authenticated requests to: {target}", fg=typer.colors.CYAN)
145
+
146
+ socketserver.TCPServer.allow_reuse_address = True
147
+ with socketserver.TCPServer(("", port), CloudRunProxyHandler) as httpd:
148
+ try:
149
+ httpd.serve_forever()
150
+ except KeyboardInterrupt:
151
+ typer.secho("\nšŸ›‘ Stopping server.", fg=typer.colors.YELLOW)