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,315 @@
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
+ """Application settings and environment variable configuration management."""
16
+
17
+ import os
18
+ from pathlib import Path
19
+
20
+ from dotenv import load_dotenv
21
+ from pydantic import Field, SecretStr, model_validator
22
+ from pydantic_settings import BaseSettings
23
+
24
+ from artemis.config.constants import (
25
+ DEFAULT_ADB_HOST,
26
+ DEFAULT_ADB_PORT,
27
+ DEFAULT_MODEL,
28
+ DEFAULT_PROFILE,
29
+ ENV_ANTHROPIC_API_KEY,
30
+ ENV_DATA_ENGINE_DB_PATH,
31
+ ENV_GCP_API_KEY,
32
+ ENV_GEMINI_API_KEY,
33
+ ENV_GOOGLE_API_KEY,
34
+ ENV_OCR_API_KEY,
35
+ ENV_OPEN_ROUTER_API_KEY,
36
+ ENV_OPENAI_API_KEY,
37
+ ENV_VISION_API_KEY,
38
+ ENV_XAI_API_KEY,
39
+ )
40
+ from artemis.config.paths import (
41
+ GLOBAL_APP_DIR,
42
+ get_data_engine_db_path,
43
+ get_default_traces_path,
44
+ get_env_file,
45
+ get_temp_dir,
46
+ )
47
+ from third_party.mobile_use.utils.logger import get_logger
48
+
49
+ # Installed wheels load .env from the user directory, outside site-packages.
50
+ _canonical_env = get_env_file()
51
+ load_dotenv(dotenv_path=_canonical_env, verbose=True)
52
+ _global_env = GLOBAL_APP_DIR / ".env"
53
+ if _global_env.exists() and _global_env.resolve() != _canonical_env.resolve():
54
+ load_dotenv(dotenv_path=_global_env, verbose=True)
55
+
56
+ logger = get_logger(__name__)
57
+
58
+
59
+ def is_placeholder_key(val: str | SecretStr | None) -> bool:
60
+ """Check if an API credential is empty or an unconfigured placeholder value."""
61
+ if val is None:
62
+ return True
63
+ raw_str = val.get_secret_value() if isinstance(val, SecretStr) else str(val)
64
+ raw_str = raw_str.strip().lower()
65
+ if not raw_str:
66
+ return True
67
+ if raw_str in (
68
+ "api_key",
69
+ "your_api_key",
70
+ "your_api_key_here",
71
+ "your_gemini_api_key_here",
72
+ "your_google_cloud_vision_api_key_here",
73
+ "your_openai_api_key_here",
74
+ "your_anthropic_api_key_here",
75
+ "your_openrouter_api_key_here",
76
+ "your_xai_api_key_here",
77
+ "none",
78
+ "empty",
79
+ "null",
80
+ "undefined",
81
+ ):
82
+ return True
83
+ if (
84
+ (raw_str.startswith("your_") and raw_str.endswith("_here"))
85
+ or (raw_str.startswith("<") and raw_str.endswith(">"))
86
+ or (raw_str.startswith("[") and raw_str.endswith("]"))
87
+ ):
88
+ return True
89
+ return False
90
+
91
+
92
+ class Settings(BaseSettings):
93
+ """Centralized ARTEMIS runtime settings loaded from environment and .env files."""
94
+
95
+ # LLM Provider Authentication
96
+ OPENAI_API_KEY: SecretStr | None = None
97
+ GOOGLE_API_KEY: SecretStr | None = None
98
+ GEMINI_API_KEY: SecretStr | None = None
99
+ GCP_API_KEY: SecretStr | None = None
100
+ ANTHROPIC_API_KEY: SecretStr | None = None
101
+ XAI_API_KEY: SecretStr | None = None
102
+ OPEN_ROUTER_API_KEY: SecretStr | None = None
103
+
104
+ # Google Cloud Vision OCR Authentication
105
+ OCR_API_KEY: SecretStr | None = None
106
+ VISION_API_KEY: SecretStr | None = None
107
+ API_KEY: SecretStr | None = None
108
+
109
+ # Custom Provider Endpoints
110
+ OPENAI_BASE_URL: str | None = None
111
+
112
+ # Android ADB Connectivity
113
+ ADB_HOST: str | None = Field(default=DEFAULT_ADB_HOST)
114
+ ADB_PORT: int | None = Field(default=DEFAULT_ADB_PORT)
115
+ ADB_DEVICE_SERIAL: str | None = None
116
+ # UI hierarchy backend: "auto" = Accessibility Helper with UIAutomator2
117
+ # fallback, "helper" = helper only, "uiautomator" = UIAutomator2 only.
118
+ ARTEMIS_HIERARCHY_BACKEND: str = Field(default="auto")
119
+ # Whether a task may install / upgrade the Accessibility Helper APK on a device
120
+ # it holds. False = only attach to a helper installed by `artemis helper install`.
121
+ ARTEMIS_HELPER_AUTO_INSTALL: bool = Field(default=True)
122
+
123
+ # Execution Defaults
124
+ PROJECT_NAME: str | None = None
125
+ ARTEMIS_DEFAULT_PROFILE: str = Field(default=DEFAULT_PROFILE)
126
+ ARTEMIS_DEFAULT_MODEL: str = Field(default=DEFAULT_MODEL)
127
+
128
+ # Explorer Tool Settings (the tier itself is configured in artemis.jsonc or
129
+ # via ARTEMIS_EXPLORER_VERSION; see artemis.config.agent.ExplorerConfig)
130
+ EXPLORER_CACHING: bool | None = Field(
131
+ default=None,
132
+ description=(
133
+ "Environment-level override for Explorer context caching; unset"
134
+ " defers to the agent configuration and the tier default."
135
+ ),
136
+ )
137
+
138
+ # LLM Reliability
139
+ LLM_PAUSE_TIMEOUT_SECONDS: float = Field(
140
+ default=900.0,
141
+ description=(
142
+ "How long a task waits in the paused state after exhausting LLM"
143
+ " retries before failing with LLMExhaustedError. <= 0 waits"
144
+ " forever (legacy interactive behavior)."
145
+ ),
146
+ )
147
+
148
+ # Paths & Storage
149
+ TRACES_PATH: Path = Field(default_factory=get_default_traces_path)
150
+ DATA_ENGINE_DB_PATH: Path = Field(default_factory=get_data_engine_db_path)
151
+ TEMP_PATH: Path = Field(default_factory=get_temp_dir)
152
+
153
+ model_config = {"env_file": ".env", "extra": "ignore"}
154
+
155
+ @model_validator(mode="after")
156
+ def fallback_api_keys(self) -> "Settings":
157
+ """Normalize Google / Gemini / GCP and OCR API keys and filter placeholders."""
158
+ # Sanitize any placeholder values loaded from environment or .env
159
+ for attr in (
160
+ "OPENAI_API_KEY",
161
+ "GOOGLE_API_KEY",
162
+ "GEMINI_API_KEY",
163
+ "GCP_API_KEY",
164
+ "ANTHROPIC_API_KEY",
165
+ "XAI_API_KEY",
166
+ "OPEN_ROUTER_API_KEY",
167
+ "OCR_API_KEY",
168
+ "VISION_API_KEY",
169
+ "API_KEY",
170
+ ):
171
+ val = getattr(self, attr, None)
172
+ if val and is_placeholder_key(val):
173
+ setattr(self, attr, None)
174
+
175
+ if not self.GOOGLE_API_KEY:
176
+ if self.GEMINI_API_KEY:
177
+ self.GOOGLE_API_KEY = self.GEMINI_API_KEY
178
+ elif self.GCP_API_KEY:
179
+ self.GOOGLE_API_KEY = self.GCP_API_KEY
180
+
181
+ # Fallback for OCR & Vision API keys
182
+ if not self.OCR_API_KEY and self.VISION_API_KEY:
183
+ self.OCR_API_KEY = self.VISION_API_KEY
184
+ return self
185
+
186
+ def get_api_key(self, provider: str) -> SecretStr | None:
187
+ """Get API key for a specified provider.
188
+
189
+ Args:
190
+ provider: Provider name (e.g., 'google', 'gemini', 'openai', 'ocr', 'vision').
191
+
192
+ Returns:
193
+ SecretStr containing the API key or None if not configured.
194
+ """
195
+ from artemis.llm.google.provider import is_google_family_provider
196
+
197
+ provider_lower = provider.lower()
198
+ key: SecretStr | None = None
199
+ if is_google_family_provider(provider_lower):
200
+ key = self.GOOGLE_API_KEY or self.GEMINI_API_KEY or self.GCP_API_KEY
201
+ elif provider_lower in ("ocr", "vision", "google_vision"):
202
+ key = self.OCR_API_KEY or self.VISION_API_KEY
203
+ elif provider_lower == "openai":
204
+ key = self.OPENAI_API_KEY
205
+ elif provider_lower in ("anthropic", "claude"):
206
+ key = self.ANTHROPIC_API_KEY
207
+ elif provider_lower == "openrouter":
208
+ key = self.OPEN_ROUTER_API_KEY
209
+ elif provider_lower in ("xai", "grok"):
210
+ key = self.XAI_API_KEY
211
+
212
+ if key and not is_placeholder_key(key):
213
+ return key
214
+ return None
215
+
216
+ def set_api_key(self, provider: str, key: str, persist_to_env: bool = False) -> None:
217
+ """Dynamically set an API key at runtime, optionally persisting to .env in the app dir.
218
+
219
+ Args:
220
+ provider: Target provider name.
221
+ key: Secret API key string.
222
+ persist_to_env: Whether to save the key to the app directory's .env file.
223
+ """
224
+ secret = SecretStr(key)
225
+ from artemis.llm.google.provider import is_google_family_provider
226
+
227
+ provider_lower = provider.lower()
228
+ env_key_name = None
229
+
230
+ if is_google_family_provider(provider_lower):
231
+ self.GOOGLE_API_KEY = secret
232
+ self.GEMINI_API_KEY = secret
233
+ self.GCP_API_KEY = secret
234
+ env_key_name = ENV_GEMINI_API_KEY
235
+ os.environ[ENV_GOOGLE_API_KEY] = key
236
+ os.environ[ENV_GEMINI_API_KEY] = key
237
+ os.environ[ENV_GCP_API_KEY] = key
238
+ elif provider_lower == "openai":
239
+ self.OPENAI_API_KEY = secret
240
+ env_key_name = ENV_OPENAI_API_KEY
241
+ os.environ[ENV_OPENAI_API_KEY] = key
242
+ elif provider_lower in ("anthropic", "claude"):
243
+ self.ANTHROPIC_API_KEY = secret
244
+ env_key_name = ENV_ANTHROPIC_API_KEY
245
+ os.environ[ENV_ANTHROPIC_API_KEY] = key
246
+ elif provider_lower == "openrouter":
247
+ self.OPEN_ROUTER_API_KEY = secret
248
+ env_key_name = ENV_OPEN_ROUTER_API_KEY
249
+ os.environ[ENV_OPEN_ROUTER_API_KEY] = key
250
+ elif provider_lower == "xai":
251
+ self.XAI_API_KEY = secret
252
+ env_key_name = ENV_XAI_API_KEY
253
+ os.environ[ENV_XAI_API_KEY] = key
254
+ elif provider_lower in ("ocr", "vision", "google_vision"):
255
+ self.OCR_API_KEY = secret
256
+ self.VISION_API_KEY = secret
257
+ env_key_name = ENV_OCR_API_KEY
258
+ os.environ[ENV_OCR_API_KEY] = key
259
+ os.environ[ENV_VISION_API_KEY] = key
260
+
261
+ if persist_to_env and env_key_name:
262
+ target_env_files = [get_env_file()]
263
+ seen_paths = set()
264
+ for env_file in target_env_files:
265
+ try:
266
+ env_file.parent.mkdir(parents=True, exist_ok=True)
267
+ resolved = env_file.resolve()
268
+ if resolved in seen_paths:
269
+ continue
270
+ seen_paths.add(resolved)
271
+
272
+ lines = []
273
+ if env_file.exists():
274
+ lines = env_file.read_text(encoding="utf-8").splitlines()
275
+
276
+ # Determine keys to update
277
+ keys_to_update = [env_key_name]
278
+ if is_google_family_provider(provider_lower):
279
+ keys_to_update = [ENV_GEMINI_API_KEY, ENV_GOOGLE_API_KEY, ENV_GCP_API_KEY]
280
+ elif provider_lower in ("ocr", "vision", "google_vision"):
281
+ keys_to_update = [ENV_OCR_API_KEY, ENV_VISION_API_KEY]
282
+
283
+ new_lines = []
284
+ updated_set = set()
285
+ for line in lines:
286
+ replaced = False
287
+ for k in keys_to_update:
288
+ if (
289
+ line.startswith(f"{k}=")
290
+ or line.startswith(f"#{k}=")
291
+ or line.startswith(f"# {k}=")
292
+ ):
293
+ new_lines.append(f"{k}={key}")
294
+ updated_set.add(k)
295
+ replaced = True
296
+ break
297
+ if not replaced:
298
+ new_lines.append(line)
299
+
300
+ # Ensure the primary key is present if not replaced
301
+ primary_key = keys_to_update[0]
302
+ if primary_key not in updated_set:
303
+ new_lines.append(f"{primary_key}={key}")
304
+
305
+ env_file.write_text("\n".join(new_lines) + "\n", encoding="utf-8")
306
+ except Exception as e:
307
+ logger.warning(f"Could not persist {env_key_name} to {env_file}: {e}")
308
+
309
+
310
+ # Singleton instance
311
+ settings = Settings()
312
+
313
+ # Synchronize DATA_ENGINE_DB_PATH in environment for external sub-processes/tools
314
+ if settings.DATA_ENGINE_DB_PATH:
315
+ os.environ[ENV_DATA_ENGINE_DB_PATH] = str(settings.DATA_ENGINE_DB_PATH)
@@ -0,0 +1,47 @@
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
+ RECURSION_LIMIT = 30000
16
+
17
+ # Optimization Constants
18
+ CHECKER_MAX_ITERATIONS = 20
19
+ VALIDATOR_POLL_TIMEOUT = 2.0
20
+ VALIDATOR_POLL_INTERVAL = 0.2
21
+ VALIDATOR_OCR_INTERVAL = 1.0
22
+ VALIDATOR_UI_HIERARCHY_TIMEOUT = 1.0
23
+
24
+ from google.genai import types as _genai_types
25
+
26
+ SAFETY_SETTINGS_BLOCK_NONE = [
27
+ _genai_types.SafetySetting(
28
+ category=_genai_types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
29
+ threshold=_genai_types.HarmBlockThreshold.BLOCK_NONE,
30
+ ),
31
+ _genai_types.SafetySetting(
32
+ category=_genai_types.HarmCategory.HARM_CATEGORY_HARASSMENT,
33
+ threshold=_genai_types.HarmBlockThreshold.BLOCK_NONE,
34
+ ),
35
+ _genai_types.SafetySetting(
36
+ category=_genai_types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
37
+ threshold=_genai_types.HarmBlockThreshold.BLOCK_NONE,
38
+ ),
39
+ _genai_types.SafetySetting(
40
+ category=_genai_types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
41
+ threshold=_genai_types.HarmBlockThreshold.BLOCK_NONE,
42
+ ),
43
+ _genai_types.SafetySetting(
44
+ category=_genai_types.HarmCategory.HARM_CATEGORY_CIVIC_INTEGRITY,
45
+ threshold=_genai_types.HarmBlockThreshold.BLOCK_NONE,
46
+ ),
47
+ ]
@@ -0,0 +1,289 @@
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
+ """Runtime context shared by Artemis agents, tools and drivers for a single task run."""
16
+
17
+ from __future__ import annotations
18
+
19
+ import asyncio
20
+
21
+ from pathlib import Path
22
+ from typing import Any, Literal, TYPE_CHECKING
23
+
24
+ if TYPE_CHECKING:
25
+ from artemis.data_engine.engine import DataEngine
26
+
27
+ try:
28
+ from adbutils import AdbClient
29
+ except ImportError:
30
+ AdbClient = Any
31
+
32
+ from pydantic import BaseModel, ConfigDict, Field, PrivateAttr
33
+ from artemis.utils.video import detect_video_tools_enabled
34
+
35
+
36
+ from artemis.config import ExplorerConfig, LLMConfig, OutputterConfig
37
+
38
+
39
+ from third_party.mobile_use.context import (
40
+ AppLaunchResult,
41
+ DeviceContext,
42
+ DeviceClientAccessors,
43
+ DevicePlatform,
44
+ ExecutionSetupBase,
45
+ )
46
+ from third_party.mobile_use.utils.logger import get_logger
47
+
48
+ logger = get_logger(__name__)
49
+
50
+
51
+ class ExecutionSetup(ExecutionSetupBase):
52
+ """Execution setup for a task."""
53
+
54
+ video_recording_tools_enabled: bool = Field(default_factory=detect_video_tools_enabled)
55
+ disable_checker: bool = False
56
+ """Legacy master switch (compat alias): ``True`` disables BOTH the midway
57
+ checkpoints and the final check, regardless of the individual gates below.
58
+ Factory default is ``False``: the exit final review runs out of the box."""
59
+ disable_midway_checks: bool = True
60
+ """Midway checkpoints are OFF by default (factory layering: final check on,
61
+ planner validation on, midway checks off)."""
62
+ disable_final_check: bool = False
63
+ checker_max_iterations: int = 20
64
+ final_check_max_attempts: int = 3
65
+ checkpoint_max_repairs: int = 2
66
+ max_concurrent_checkpoints: int = 3
67
+ checkpoint_timeout: float = 180.0
68
+ settlement_timeout: float = 120.0
69
+ assert_failure_policy: Literal["continue", "halt"] = "continue"
70
+ disable_device_probes: bool = False
71
+ disable_planner_validation: bool = False
72
+ enable_committee: bool = False
73
+ committee_debate_rounds: int = 2
74
+ disable_outputter: bool = False
75
+ outputter: OutputterConfig = Field(default_factory=OutputterConfig)
76
+ explorer: ExplorerConfig = Field(default_factory=ExplorerConfig)
77
+ explorer_versions: dict[str, str] = Field(default_factory=dict)
78
+
79
+ @property
80
+ def midway_checks_enabled(self) -> bool:
81
+ """Midway checkpoint gate: honors both the individual switch and the
82
+ legacy ``disable_checker`` master alias."""
83
+ return not (self.disable_midway_checks or self.disable_checker)
84
+
85
+ @property
86
+ def final_check_enabled(self) -> bool:
87
+ """Final review gate: honors both the individual switch and the legacy
88
+ ``disable_checker`` master alias."""
89
+ return not (self.disable_final_check or self.disable_checker)
90
+
91
+ @property
92
+ def checks_enabled(self) -> bool:
93
+ """True when any check gate is active (drives conditional prompt assembly)."""
94
+ return self.midway_checks_enabled or self.final_check_enabled
95
+
96
+ @property
97
+ def explorer_version(self) -> str:
98
+ return self.explorer.default_version
99
+
100
+ @property
101
+ def explorer_flash_mode(self) -> str:
102
+ return self.explorer.flash_mode
103
+
104
+ @property
105
+ def explorer_pro_mode(self) -> str:
106
+ return self.explorer.pro_mode
107
+
108
+ @property
109
+ def explorer_caching(self) -> bool | None:
110
+ return self.explorer.caching
111
+
112
+
113
+ class ArtemisContext(DeviceClientAccessors, BaseModel):
114
+ model_config = ConfigDict(
115
+ arbitrary_types_allowed=True,
116
+ extra="allow",
117
+ )
118
+
119
+ device: DeviceContext
120
+ llm_config: LLMConfig | None = None
121
+ agent_config: Any = None
122
+ adb_client: Any | None = None
123
+ ui_adb_client: Any | None = None
124
+ adb_task_registry: Any | None = None
125
+ """Per-task ADB background-task registry (``artemis.tools.command_tool``).
126
+ Created lazily on first ADB tool use; killed at task end."""
127
+
128
+ execution_setup: ExecutionSetup | None = None
129
+
130
+ data_engine: DataEngine | None = None
131
+ planner_task: asyncio.Task[Any] | None = None
132
+ background_tasks: list[asyncio.Task[Any]] = Field(default_factory=list)
133
+ background_task_grace_period_seconds: float = 2.0
134
+ package_cache: dict[str, str | None] = Field(default_factory=dict)
135
+ background_jobs: dict[str, dict[str, Any]] = Field(default_factory=dict)
136
+
137
+ pending_checkpoints: list[Any] = Field(default_factory=list)
138
+ """Queued :class:`~artemis.graph.checkpoints.PendingCheckpoint` entries.
139
+ ``_process_plan_write`` only enqueues; ``execution_check_node`` spawns after
140
+ the turn's step is recorded so the evidence anchor points at a real step."""
141
+ checkpoint_tasks: dict[str, Any] = Field(default_factory=dict)
142
+ """checkpoint_id -> (attempt_id, asyncio.Task). One in-flight attempt per
143
+ checkpoint; supersede harvests/cancels the old entry before replacing it."""
144
+ checkpoint_attempt_seq: dict[str, int] = Field(default_factory=dict)
145
+ """checkpoint_id -> monotonically increasing attempt counter."""
146
+ checkpoint_repairs: dict[str, int] = Field(default_factory=dict)
147
+ """checkpoint_id -> number of verify-fail repairs already applied."""
148
+ assert_halt: bool = False
149
+ """Latched by an assert failure under ``assert_failure_policy='halt'``."""
150
+ final_check_attempts: int = 0
151
+ """Number of final-check passes already executed at exit settlement."""
152
+
153
+ last_validated_plan: str | None = None
154
+ """Ratchet baseline for planner validation: the last plan content whose
155
+ top-level milestones were validated (or the initial plan). Drift is always
156
+ judged against this, never against the immediately preceding write."""
157
+ pending_validated_plan: str | None = None
158
+ """Plan content currently under async planner validation; becomes the new
159
+ baseline when the validator approves it."""
160
+
161
+ guidance_unprotected_checks: set[tuple[str, str]] = Field(default_factory=set)
162
+ """``(kind, text)`` of every check line that existed in the task plan when a
163
+ mid-run user instruction arrived. User guidance outranks the plan's declared
164
+ standards, so these lines lose their machine restoration for the rest of the
165
+ run (the Operator may drop or reword them at any later write); check lines
166
+ added afterwards stay protected until the next instruction."""
167
+ guidance_retired_checks: set[tuple[str, str]] = Field(default_factory=set)
168
+ """``(kind, text)`` of the check lines the Operator actually dropped under
169
+ that waiver. A verdict recorded for such a line before it was retired is a
170
+ result for a requirement the user withdrew: the run outcome reports it as
171
+ retired instead of counting it as a pass or failure."""
172
+
173
+ _genai_client: Any | None = PrivateAttr(default=None)
174
+ _video_blackboard: Any | None = PrivateAttr(default=None)
175
+ _video_circuit_breaker: Any | None = PrivateAttr(default=None)
176
+ _mobile_controller: Any | None = PrivateAttr(default=None)
177
+ _active_driver: Any | None = PrivateAttr(default=None)
178
+ """Cached device driver singleton (artemis.drivers.factory.get_driver)."""
179
+ mcp_client_ctx: Any | None = None
180
+ mcp_session: Any | None = None
181
+ action_session: Any | None = None
182
+ """In-process unified action MCP session (artemis.mcp.action_session)."""
183
+ actuator: Any | None = None
184
+ """Optional actuator backend override (artemis.mcp.actuators). ``None`` selects
185
+ the default AdbActuator; installing e.g. a robot-arm backend happens here."""
186
+
187
+ step_memory: Any | None = None
188
+ """Shared :class:`~artemis.memory.step_memory.StepMemoryService` composition
189
+ root (history redesign §6.2). Created on first use via
190
+ ``artemis.memory.ensure_step_memory``; Flash and Pro profiles share one
191
+ instance so summary jobs, retries, and flush semantics are unified."""
192
+
193
+ transcript_ledger: Any | None = None
194
+ """Session :class:`~artemis.memory.transcript.TranscriptLedger` for the Pro
195
+ operator's transcript prompt path (``agent.memory.transcript.enabled``).
196
+ Lives beside ``step_memory``; the State never carries message payloads."""
197
+
198
+ async def __aenter__(self) -> ArtemisContext:
199
+ return self
200
+
201
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
202
+ # Close the in-process action session before draining background tasks so its
203
+ # owner task exits cleanly rather than being cancelled below.
204
+ if self.action_session is not None:
205
+ try:
206
+ await self.action_session.aclose()
207
+ except Exception as exc:
208
+ logger.debug(f"Action session close failed; skipped: {exc}", exc_info=True)
209
+ finally:
210
+ self.action_session = None
211
+
212
+ # Drain in-flight step-summary jobs before the generic background-task
213
+ # sweep: the shared service owns its own bounded flush semantics. On an
214
+ # exceptional exit the flush is skipped and the jobs are cancelled below.
215
+ if self.step_memory is not None and callable(getattr(self.step_memory, "flush", None)):
216
+ try:
217
+ if exc_type is None:
218
+ await self.step_memory.flush()
219
+ else:
220
+ await self.step_memory.flush(timeout_seconds=0.0)
221
+ except Exception as exc:
222
+ logger.debug(f"Step-memory flush failed; skipped: {exc}", exc_info=True)
223
+
224
+ # Drain in-flight chunk capsule jobs the same way (M3): the chunk
225
+ # manager persists any harvested capsules so the DB copy is complete
226
+ # even though the frozen transcript text is not re-rendered.
227
+ chunker = getattr(self.transcript_ledger, "chunker", None)
228
+ if chunker is not None and callable(getattr(chunker, "flush", None)):
229
+ try:
230
+ if exc_type is None:
231
+ await chunker.flush()
232
+ else:
233
+ await chunker.flush(timeout_seconds=0.0)
234
+ except Exception as exc:
235
+ logger.debug(f"History chunk flush failed; skipped: {exc}", exc_info=True)
236
+
237
+ if self.background_tasks:
238
+ tasks = list(self.background_tasks)
239
+ pending_tasks = [task for task in tasks if not task.done()]
240
+ grace_period = (
241
+ max(0.0, self.background_task_grace_period_seconds) if exc_type is None else 0.0
242
+ )
243
+
244
+ if pending_tasks and grace_period > 0:
245
+ logger.info(
246
+ f"Draining {len(pending_tasks)} background tasks for up to "
247
+ f"{grace_period:.1f}s..."
248
+ )
249
+ _, pending_tasks = await asyncio.wait(
250
+ pending_tasks,
251
+ timeout=grace_period,
252
+ )
253
+
254
+ if pending_tasks:
255
+ logger.info(
256
+ f"Cancelling {len(pending_tasks)} unfinished background tasks; "
257
+ "primary automation is already complete."
258
+ )
259
+ for task in pending_tasks:
260
+ task.cancel()
261
+
262
+ results = await asyncio.gather(*tasks, return_exceptions=True)
263
+ for task, result in zip(tasks, results):
264
+ if isinstance(result, Exception):
265
+ logger.error(
266
+ f"Background task {task.get_name()} failed: {result}",
267
+ exc_info=result,
268
+ )
269
+ self.background_tasks.clear()
270
+
271
+ if self.mcp_client_ctx:
272
+ try:
273
+ await self.mcp_client_ctx.__aexit__(exc_type, exc_val, exc_tb)
274
+ except Exception as exc:
275
+ logger.debug(f"MCP client context exit failed; skipped: {exc}", exc_info=True)
276
+ finally:
277
+ self.mcp_client_ctx = None
278
+ self.mcp_session = None
279
+
280
+ if self.data_engine:
281
+ try:
282
+ await self.data_engine.shutdown()
283
+ except Exception as exc:
284
+ logger.debug(f"DataEngine shutdown failed; skipped: {exc}", exc_info=True)
285
+
286
+
287
+ from artemis.data_engine.engine import DataEngine
288
+
289
+ ArtemisContext.model_rebuild()
@@ -0,0 +1,41 @@
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
+ """Backward compatibility layer for legacy artemis.controllers module.
16
+ All new development should use artemis.drivers instead.
17
+ """
18
+
19
+ from artemis.drivers.base import BaseDeviceDriver, KeyCode, ScreenData, SwipeDirection
20
+ from artemis.drivers.factory import create_driver, get_driver
21
+ from artemis.drivers.types import (
22
+ Bounds,
23
+ CoordinatesSelectorRequest,
24
+ PercentagesSelectorRequest,
25
+ SwipeRequest,
26
+ TapOutput,
27
+ )
28
+
29
+ __all__ = [
30
+ "BaseDeviceDriver",
31
+ "KeyCode",
32
+ "ScreenData",
33
+ "SwipeDirection",
34
+ "Bounds",
35
+ "CoordinatesSelectorRequest",
36
+ "PercentagesSelectorRequest",
37
+ "SwipeRequest",
38
+ "TapOutput",
39
+ "create_driver",
40
+ "get_driver",
41
+ ]