android-midscene-automation 0.2.4 → 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.
Files changed (525) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +35 -0
  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,404 @@
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
+ """UI Launch and Web Console CLI Command (artemis ui)."""
16
+
17
+ import logging
18
+ from pathlib import Path
19
+ import re
20
+ import shutil
21
+ import subprocess
22
+ import sys
23
+ import threading
24
+ import time
25
+ from typing import Annotated
26
+ import urllib.request
27
+ import webbrowser
28
+
29
+ from rich.console import Console
30
+ from rich.markup import escape
31
+ from rich.panel import Panel
32
+ import typer
33
+
34
+ logger = logging.getLogger(__name__)
35
+
36
+
37
+ def running_via_console_script_shim() -> bool:
38
+ """Return True when this CLI was launched through a console-script ``.exe`` shim.
39
+
40
+ On Windows, ``uv``/pip install entry points as trampoline executables
41
+ (``Scripts/artemis.exe``) that stay resident for the lifetime of the CLI
42
+ process and hold a lock on their own file. A long-running foreground server
43
+ started through the shim therefore blocks ``uv sync`` from reinstalling the
44
+ package ("os error 32") until the server exits. Launching via
45
+ ``python -m artemis`` avoids the shim entirely.
46
+ """
47
+ if sys.platform != "win32":
48
+ return False
49
+ argv0 = Path(sys.argv[0] or "")
50
+ return argv0.suffix.lower() == ".exe" and argv0.name.lower() != "python.exe"
51
+
52
+
53
+ def warn_if_console_script_shim(console: Console) -> None:
54
+ """Print a hint when a foreground server run will pin the console-script exe."""
55
+ if running_via_console_script_shim():
56
+ console.print(
57
+ " [dim]⚠ Running in foreground via the [bold]artemis.exe[/bold] launcher: package "
58
+ "syncs (uv sync / uv run) cannot replace it while this server is running.\n"
59
+ " Prefer [bold]artemis restart[/bold] (background daemon) or launch with "
60
+ "[bold]uv run python -m artemis ui[/bold] to avoid this.[/dim]\n"
61
+ )
62
+
63
+
64
+ def _resolve_npm_executable(platform_name: str | None = None) -> str | None:
65
+ """Return a directly executable npm path for the current platform."""
66
+ platform_name = platform_name or sys.platform
67
+ candidates = ("npm.cmd", "npm.exe", "npm") if platform_name == "win32" else ("npm",)
68
+ return next((path for candidate in candidates if (path := shutil.which(candidate))), None)
69
+
70
+
71
+ def _showcase_build_required(showcase_dir: Path) -> bool:
72
+ """Return whether the compiled Angular app is missing or older than its inputs."""
73
+ base_dist = showcase_dir / "dist"
74
+ candidates = [
75
+ base_dist / "frontend" / "browser" / "index.html",
76
+ base_dist / "browser" / "index.html",
77
+ base_dist / "frontend" / "index.html",
78
+ base_dist / "index.html",
79
+ ]
80
+ built_indexes = [path for path in candidates if path.exists()]
81
+ if not built_indexes:
82
+ return True
83
+
84
+ build_time = max(path.stat().st_mtime for path in built_indexes)
85
+ input_paths = [showcase_dir / "package.json", showcase_dir / "angular.json"]
86
+ source_dir = showcase_dir / "src"
87
+ if source_dir.exists():
88
+ input_paths.extend(path for path in source_dir.rglob("*") if path.is_file())
89
+ return any(path.exists() and path.stat().st_mtime > build_time for path in input_paths)
90
+
91
+
92
+ def _npm_install_required(showcase_dir: Path) -> bool:
93
+ """Return whether ``node_modules`` is missing or older than the package manifests.
94
+
95
+ npm rewrites ``node_modules/.package-lock.json`` on every successful
96
+ install, so its mtime is the "dependencies last synced" stamp.
97
+ """
98
+ stamp = showcase_dir / "node_modules" / ".package-lock.json"
99
+ if not stamp.exists():
100
+ return True
101
+ synced_at = stamp.stat().st_mtime
102
+ manifests = (showcase_dir / "package.json", showcase_dir / "package-lock.json")
103
+ return any(path.exists() and path.stat().st_mtime > synced_at for path in manifests)
104
+
105
+
106
+ _ANSI_ESCAPE_RE = re.compile(r"\x1b\[[0-?]*[ -/]*[@-~]")
107
+ _HEARTBEAT_INTERVAL_SECONDS = 15.0
108
+
109
+
110
+ def _format_elapsed(seconds: float) -> str:
111
+ """``42s`` / ``3m 51s``."""
112
+ whole = int(seconds)
113
+ if whole < 60:
114
+ return f"{whole}s"
115
+ return f"{whole // 60}m {whole % 60:02d}s"
116
+
117
+
118
+ def _run_build_step(console: Console, label: str, cmd: list[str], cwd: Path) -> None:
119
+ """Run one build step, relaying its output live and raising on failure.
120
+
121
+ The child's stdout/stderr are forwarded line by line (ANSI stripped,
122
+ indented, dimmed) so npm summaries, ``ng build`` progress and any error
123
+ reach the terminal as they happen. On an interactive terminal a spinner
124
+ with the elapsed time keeps ticking through the long silent phases
125
+ (downloads, bundling); without a TTY a plain heartbeat line is printed
126
+ every 15 seconds instead so logs are not flooded with spinner frames.
127
+ """
128
+ started = time.monotonic()
129
+ console.print(f" [bold]{label}[/bold]")
130
+ process = subprocess.Popen(
131
+ cmd,
132
+ cwd=cwd,
133
+ stdout=subprocess.PIPE,
134
+ stderr=subprocess.STDOUT,
135
+ text=True,
136
+ encoding="utf-8",
137
+ errors="replace",
138
+ )
139
+ assert process.stdout is not None
140
+
141
+ def relay_line(raw: str) -> None:
142
+ line = _ANSI_ESCAPE_RE.sub("", raw).rstrip()
143
+ if line.strip():
144
+ console.print(f" {escape(line)}", style="dim", highlight=False)
145
+
146
+ def stream_output(status=None) -> None:
147
+ last_heartbeat = started
148
+ for raw in process.stdout:
149
+ relay_line(raw)
150
+ now = time.monotonic()
151
+ if status is not None:
152
+ status.update(f"{label} … {_format_elapsed(now - started)}")
153
+ elif now - last_heartbeat >= _HEARTBEAT_INTERVAL_SECONDS:
154
+ console.print(f" still running… {_format_elapsed(now - started)}")
155
+ last_heartbeat = now
156
+
157
+ if console.is_terminal:
158
+ with console.status(f"{label} … 0s", spinner="dots") as status:
159
+ ticker_stop = threading.Event()
160
+
161
+ def tick() -> None:
162
+ while not ticker_stop.wait(1.0):
163
+ status.update(f"{label} … {_format_elapsed(time.monotonic() - started)}")
164
+
165
+ ticker = threading.Thread(target=tick, daemon=True)
166
+ ticker.start()
167
+ try:
168
+ stream_output(status)
169
+ finally:
170
+ ticker_stop.set()
171
+ ticker.join(timeout=2.0)
172
+ else:
173
+ heartbeat_stop = threading.Event()
174
+
175
+ def heartbeat() -> None:
176
+ while not heartbeat_stop.wait(_HEARTBEAT_INTERVAL_SECONDS):
177
+ console.print(f" still running… {_format_elapsed(time.monotonic() - started)}")
178
+
179
+ beat = threading.Thread(target=heartbeat, daemon=True)
180
+ beat.start()
181
+ try:
182
+ stream_output()
183
+ finally:
184
+ heartbeat_stop.set()
185
+ beat.join(timeout=2.0)
186
+
187
+ returncode = process.wait()
188
+ if returncode != 0:
189
+ raise subprocess.CalledProcessError(returncode, cmd)
190
+
191
+
192
+ def ensure_showcase_built(console: Console) -> None:
193
+ """Rebuild the Angular Showcase UI when its sources are newer than the dist build."""
194
+ from artemis.config.paths import ROOT_DIR
195
+ from artemis.resources import get_bundled_showcase_dist
196
+
197
+ showcase_dir = ROOT_DIR / "apps" / "showcase_ui"
198
+ # An installed wheel has no frontend source tree; its immutable build is
199
+ # prepared during packaging and must never trigger npm at runtime.
200
+ if not showcase_dir.is_dir() and get_bundled_showcase_dist() is not None:
201
+ return
202
+ if not _showcase_build_required(showcase_dir):
203
+ return
204
+ npm_executable = _resolve_npm_executable()
205
+ if not npm_executable:
206
+ return
207
+ console.print(
208
+ " [yellow]🎨 Showcase UI sources changed. Compiling Angular Showcase UI...[/yellow]"
209
+ )
210
+ started = time.monotonic()
211
+ try:
212
+ if _npm_install_required(showcase_dir):
213
+ _run_build_step(
214
+ console,
215
+ "① npm install (dependencies changed)",
216
+ [npm_executable, "install", "--no-audit", "--no-fund", "--loglevel=warn"],
217
+ showcase_dir,
218
+ )
219
+ _run_build_step(console, "② ng build", [npm_executable, "run", "build"], showcase_dir)
220
+ console.print(
221
+ f" [green]✓ Showcase UI built in {_format_elapsed(time.monotonic() - started)}."
222
+ "[/green]\n"
223
+ )
224
+ except Exception as e:
225
+ console.print(
226
+ f" [red]⚠ Failed to auto-build Showcase UI: {e}[/red]\n"
227
+ " [dim]Build it by hand with: cd apps/showcase_ui && npm install && "
228
+ "npm run build[/dim]\n"
229
+ )
230
+
231
+
232
+ def load_session_reconciler() -> None:
233
+ """Entry-layer assembly: arm stop_server()'s orphan-session cleanup.
234
+
235
+ Importing the admin console session repository registers its reconciler
236
+ with ``artemis.runtime.server_lifecycle`` (inverted dependency: the base
237
+ runtime package never imports the application layer). Guarded so a broken
238
+ or absent admin console install can never block stopping a server.
239
+ """
240
+ try:
241
+ import apps.admin_console.database.repositories.session_repository # noqa: F401
242
+ except Exception as exc: # pylint: disable=broad-exception-caught
243
+ logger.debug("Admin console session reconciler not loaded: %s", exc, exc_info=True)
244
+
245
+
246
+ def _poll_and_open_browser(url: str, stop_event: threading.Event, timeout: float = 15.0) -> None:
247
+ """Poll the UI server until it responds, then launch the user's default browser."""
248
+ start = time.time()
249
+ while not stop_event.is_set() and (time.time() - start < timeout):
250
+ try:
251
+ req = urllib.request.Request(url, headers={"User-Agent": "Artemis-HealthCheck/1.0"})
252
+ with urllib.request.urlopen(req, timeout=1.5) as resp:
253
+ if resp.status == 200:
254
+ time.sleep(0.3)
255
+ webbrowser.open(url)
256
+ return
257
+ except Exception:
258
+ time.sleep(0.4)
259
+
260
+
261
+ def ui_command(
262
+ host: Annotated[
263
+ str,
264
+ typer.Option(
265
+ "--host",
266
+ "-h",
267
+ help=(
268
+ "Bind host address for the UI server. Defaults to loopback; for remote "
269
+ "access prefer a Tailscale/SSH tunnel over a wide bind."
270
+ ),
271
+ ),
272
+ ] = "127.0.0.1",
273
+ port: Annotated[
274
+ int,
275
+ typer.Option("--port", "-p", help="Port to run the unified UI server on."),
276
+ ] = 8000,
277
+ open_browser: Annotated[
278
+ bool,
279
+ typer.Option(
280
+ "--open/--no-open",
281
+ help="Automatically open the Showcase UI in default web browser.",
282
+ ),
283
+ ] = True,
284
+ reload: Annotated[
285
+ bool,
286
+ typer.Option(
287
+ "--reload/--no-reload",
288
+ help="Enable uvicorn live auto-reload (for development).",
289
+ ),
290
+ ] = False,
291
+ restart: Annotated[
292
+ bool,
293
+ typer.Option(
294
+ "--restart",
295
+ "-r",
296
+ help="Restart server by terminating any existing instance on the port first.",
297
+ ),
298
+ ] = False,
299
+ ) -> None:
300
+ """Launch the unified Artemis Showcase UI & Admin Console in one click."""
301
+ console = Console()
302
+ local_url = f"http://localhost:{port}"
303
+
304
+ from artemis.runtime.server_lifecycle import (
305
+ find_server_pids,
306
+ is_port_in_use,
307
+ stop_server,
308
+ )
309
+
310
+ if restart:
311
+ console.print(f" [yellow]🔄 Restart requested. Recycling port {port}...[/yellow]")
312
+ load_session_reconciler()
313
+ stop_server(port=port, timeout=12.0)
314
+ elif is_port_in_use(port):
315
+ pids = find_server_pids(port)
316
+ pid_str = f" (PID: {', '.join(map(str, pids))})" if pids else ""
317
+ if sys.stdin.isatty():
318
+ console.print(
319
+ f"\n [yellow]⚠ Port {port} is already in use by an active Artemis server{pid_str}.[/yellow]"
320
+ )
321
+ console.print(" [dim]Choose an action:[/dim]")
322
+ console.print(" [bold]1[/bold] Open browser (default)")
323
+ console.print(" [bold]2[/bold] Restart server (stop existing and start here)")
324
+ console.print(" [bold]3[/bold] Cancel")
325
+ try:
326
+ choice = input(" Select [1-3, default 1]: ").strip()
327
+ except (KeyboardInterrupt, EOFError):
328
+ choice = "1"
329
+ if choice == "2":
330
+ console.print(
331
+ f"\n [yellow]🔄 Terminating previous Artemis instance on port {port}...[/yellow]"
332
+ )
333
+ load_session_reconciler()
334
+ stop_server(port=port, timeout=12.0)
335
+ elif choice == "3":
336
+ return
337
+ else:
338
+ if open_browser:
339
+ webbrowser.open(local_url)
340
+ return
341
+ else:
342
+ console.print(
343
+ f"\n [yellow]⚠ Port {port} is already in use by Artemis{pid_str}. "
344
+ f"Use '[bold]artemis restart[/bold]' to restart.[/yellow]\n"
345
+ )
346
+ if open_browser:
347
+ webbrowser.open(local_url)
348
+ return
349
+
350
+ console.print()
351
+ msg = (
352
+ f"[bold cyan]✨ Artemis Autonomous Mobile Agent UI[/bold cyan]\n\n"
353
+ f"📱 [bold green]Showcase UI & Onboarding:[/bold green] [cyan]{local_url}[/cyan]\n"
354
+ f"🛠️ [bold magenta]Admin Debug Console:[/bold magenta] [cyan]{local_url}/admin[/cyan]\n"
355
+ f"📖 [dim]API Documentation:[/dim] [dim]{local_url}/docs[/dim]\n\n"
356
+ + (
357
+ "[dim]Press Ctrl+C to stop while idle; Ctrl+Break forces shutdown during a task.[/dim]"
358
+ if sys.platform == "win32"
359
+ else "[dim]Press Ctrl+C to stop the server.[/dim]"
360
+ )
361
+ )
362
+ console.print(Panel(msg, title="🚀 Web Server Active", border_style="cyan", expand=False))
363
+ # Ensure the canonical writable .env exists. Installed wheels must never
364
+ # attempt to mutate their site-packages directory.
365
+ from artemis.config.paths import ROOT_DIR, get_env_file, is_source_checkout
366
+
367
+ env_file = get_env_file()
368
+ env_example = ROOT_DIR / ".env.example"
369
+ if not env_file.exists():
370
+ env_file.parent.mkdir(parents=True, exist_ok=True)
371
+ if is_source_checkout() and env_example.exists():
372
+ try:
373
+ env_file.write_text(env_example.read_text(encoding="utf-8"), encoding="utf-8")
374
+ except (OSError, UnicodeError):
375
+ pass
376
+ else:
377
+ try:
378
+ env_file.touch()
379
+ except OSError:
380
+ pass
381
+
382
+ ensure_showcase_built(console)
383
+ warn_if_console_script_shim(console)
384
+
385
+ stop_event = threading.Event()
386
+ if open_browser:
387
+ t = threading.Thread(
388
+ target=_poll_and_open_browser,
389
+ args=(local_url, stop_event),
390
+ daemon=True,
391
+ )
392
+ t.start()
393
+
394
+ try:
395
+ # Intentional entry-layer lazy load: the CLI assembles the application
396
+ # here, and importing the FastAPI server at module import time would
397
+ # drag the whole admin console into every `artemis <cmd>` invocation.
398
+ from apps.admin_console.server import run_ui_server
399
+
400
+ run_ui_server(host=host, port=port, reload=reload)
401
+ except KeyboardInterrupt:
402
+ console.print("\n[yellow]🛑 UI Server stopped.[/yellow]")
403
+ finally:
404
+ stop_event.set()
@@ -0,0 +1,109 @@
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
+ """ARTEMIS Unified Command Line Interface (CLI)."""
16
+
17
+ from typing import Annotated
18
+
19
+ from artemis._version import __version__
20
+ from artemis.interfaces.cli.commands.batch import batch_command
21
+ from artemis.interfaces.cli.commands.doctor import doctor_command
22
+ from artemis.interfaces.cli.commands.helper import helper_app
23
+ from artemis.interfaces.cli.commands.init import init_command
24
+ from artemis.interfaces.cli.commands.mcp import mcp_command
25
+ from artemis.interfaces.cli.commands.run import run_command
26
+ from artemis.interfaces.cli.commands.server import server_app
27
+ from artemis.interfaces.cli.commands.server_lifecycle import (
28
+ restart_command,
29
+ status_command,
30
+ stop_command,
31
+ )
32
+ from artemis.interfaces.cli.commands.trace import trace_app
33
+ from artemis.interfaces.cli.commands.ui import ui_command
34
+ from third_party.mobile_use.utils.logger import get_logger
35
+ from rich.console import Console
36
+ from rich.panel import Panel
37
+ import typer
38
+
39
+ logger = get_logger(__name__)
40
+
41
+ app = typer.Typer(
42
+ name="artemis",
43
+ help="☕ Artemis: Autonomous Multimodal Android Agent & Testing Framework.",
44
+ add_completion=False,
45
+ pretty_exceptions_enable=False,
46
+ no_args_is_help=True,
47
+ )
48
+
49
+ # Register subcommands
50
+ app.command(name="ui", help="Launch the unified Showcase UI & Admin Console in your browser.")(
51
+ ui_command
52
+ )
53
+ app.command(name="restart", help="Restart running Artemis Web UI & server.")(restart_command)
54
+ app.command(name="stop", help="Stop running Artemis Web UI & server.")(stop_command)
55
+ app.command(name="status", help="Display Artemis Web UI & server status.")(status_command)
56
+ app.command(name="run", help="Execute an autonomous task on a mobile device.")(run_command)
57
+ app.command(name="init", help="Interactive quickstart wizard to configure API keys & device.")(
58
+ init_command
59
+ )
60
+ app.command(name="doctor", help="Check system prerequisites, device status, and configuration.")(
61
+ doctor_command
62
+ )
63
+ app.command(name="batch", help="Execute a batch sequence of automation tasks.")(batch_command)
64
+ app.command(name="mcp", help="Start the Artemis Model Context Protocol (MCP) server.")(mcp_command)
65
+ app.add_typer(server_app, name="server", help="Cloud Run proxy and web dashboard server.")
66
+ app.add_typer(trace_app, name="trace", help="Inspect and query execution traces.")
67
+ app.add_typer(
68
+ helper_app, name="helper", help="Manage the Accessibility Helper APK on attached devices."
69
+ )
70
+
71
+
72
+ def version_callback(value: bool):
73
+ if value:
74
+ console = Console()
75
+ console.print(
76
+ Panel(
77
+ f"[bold cyan]Artemis Agent Platform[/bold cyan] v{__version__}\n"
78
+ "[dim]Autonomous Multimodal Mobile AI Engine[/dim]",
79
+ title="☕ Artemis",
80
+ expand=False,
81
+ )
82
+ )
83
+ raise typer.Exit()
84
+
85
+
86
+ @app.callback()
87
+ def main_callback(
88
+ version: Annotated[
89
+ bool,
90
+ typer.Option(
91
+ "--version",
92
+ "-v",
93
+ help="Show Artemis version and exit.",
94
+ callback=version_callback,
95
+ is_eager=True,
96
+ ),
97
+ ] = False,
98
+ ):
99
+ """ARTEMIS Autonomous Mobile Agent CLI."""
100
+ pass
101
+
102
+
103
+ def cli():
104
+ """Main CLI entrypoint."""
105
+ app()
106
+
107
+
108
+ if __name__ == "__main__":
109
+ cli()
@@ -0,0 +1,31 @@
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
+ """Python SDK for ARTEMIS."""
16
+
17
+ from artemis.interfaces.sdk.client import ArtemisClient, ConcurrencyMode
18
+ from artemis.interfaces.sdk.task import StreamEvent, StreamEventType, Task
19
+ from artemis_client import Capabilities, Device, TaskHandle, TaskResult
20
+
21
+ __all__ = [
22
+ "ArtemisClient",
23
+ "Capabilities",
24
+ "ConcurrencyMode",
25
+ "Device",
26
+ "StreamEvent",
27
+ "StreamEventType",
28
+ "Task",
29
+ "TaskHandle",
30
+ "TaskResult",
31
+ ]
@@ -0,0 +1,19 @@
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
+ """Compatibility import for the standalone remote Artemis client.
10
+
11
+ The implementation lives in the zero-dependency ``artemis-client`` package.
12
+ Keeping this module lets existing full-runtime installations migrate without
13
+ maintaining a second client execution path.
14
+ """
15
+
16
+ from artemis.runtime import ConcurrencyMode
17
+ from artemis_client import ArtemisClient
18
+
19
+ __all__ = ["ArtemisClient", "ConcurrencyMode"]
@@ -0,0 +1,72 @@
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
+ import time
16
+ from typing import Any, Literal
17
+ from pydantic import BaseModel, Field
18
+
19
+
20
+ class StreamEventType:
21
+ THOUGHT = "thought"
22
+ ACTION = "action"
23
+ OBSERVATION = "observation"
24
+ STEP_START = "step_start"
25
+ STEP_END = "step_end"
26
+ STATUS = "status"
27
+ ERROR = "error"
28
+
29
+
30
+ class StreamEvent(BaseModel):
31
+ """Real-time intermediate progress event emitted during task execution."""
32
+
33
+ event_type: str = Field(
34
+ ..., description="Type of event: thought, action, observation, status, etc."
35
+ )
36
+ step_number: int = Field(default=0, description="1-indexed execution step")
37
+ payload: dict[str, Any] = Field(default_factory=dict, description="Event data dictionary")
38
+ timestamp: float = Field(default_factory=time.time, description="Epoch timestamp")
39
+
40
+
41
+ class Task(BaseModel):
42
+ """Configures a single autonomous mobile automation request."""
43
+
44
+ goal: str = Field(..., description="High-level goal description")
45
+ profile: Literal["flash", "pro"] = Field(default="pro", description="Execution profile")
46
+ device_id: str = Field(default="default-device", description="Target device serial")
47
+ device_serial: str | None = Field(
48
+ default=None, description="Target device serial (alias for device_id)"
49
+ )
50
+ concurrency_mode: Literal["global", "per_device"] | None = Field(
51
+ default=None,
52
+ description="Concurrency mode: 'global' (1 across all devices) or 'per_device' (1 per device)",
53
+ )
54
+ locked_package: str | None = Field(default=None, description="Package lock restriction")
55
+ max_turns: int = Field(default=30, description="Turn cutoff limit")
56
+
57
+ def model_post_init(self, __context: Any) -> None:
58
+ if self.device_serial and self.device_id == "default-device":
59
+ self.device_id = self.device_serial
60
+ elif self.device_id != "default-device" and not self.device_serial:
61
+ self.device_serial = self.device_id
62
+
63
+
64
+ class TaskResult(BaseModel):
65
+ """Final structured outcome of a task execution."""
66
+
67
+ trace_id: str
68
+ status: str
69
+ turns: int
70
+ output: Any = None
71
+ error: str | None = None
72
+ device_id: str | None = None
@@ -0,0 +1,25 @@
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
+ """LLM provider integration layer (endpoint descriptors and model factory)."""
16
+
17
+ from artemis.llm.router import (
18
+ ModelEndpoint,
19
+ ModelProvider,
20
+ )
21
+
22
+ __all__ = [
23
+ "ModelEndpoint",
24
+ "ModelProvider",
25
+ ]