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,148 @@
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 json
16
+ import logging
17
+ import time
18
+ from typing import Any
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class ModelService:
24
+ """Service handling agent architecture profile detection and metadata formatting."""
25
+
26
+ # parse_llm_config re-reads and re-validates the config file on every call;
27
+ # /api/sessions calls this once per session row, so cache (provider, model_id)
28
+ # for a short TTL. Config edits take effect within _LLM_INFO_TTL seconds.
29
+ _LLM_INFO_TTL = 10.0
30
+ _llm_info_cache: tuple[float, str, str] | None = None
31
+
32
+ @classmethod
33
+ def _get_llm_provider_and_model(cls) -> tuple[str, str]:
34
+ cached = cls._llm_info_cache
35
+ now = time.monotonic()
36
+ if cached and now - cached[0] < cls._LLM_INFO_TTL:
37
+ return cached[1], cached[2]
38
+ provider = "google"
39
+ model_id = "gemini-3.7-flash"
40
+ try:
41
+ from artemis.config import parse_llm_config
42
+
43
+ llm_cfg = parse_llm_config()
44
+ if llm_cfg and llm_cfg.operator:
45
+ provider = str(llm_cfg.operator.provider)
46
+ model_id = str(llm_cfg.operator.model)
47
+ elif llm_cfg and llm_cfg.default:
48
+ provider = str(llm_cfg.default.provider)
49
+ model_id = str(llm_cfg.default.model)
50
+ except Exception as exc:
51
+ # Unreadable/invalid LLM config: fall back to display defaults
52
+ # (cached for the TTL, so this logs at most once per window).
53
+ logger.warning("Could not resolve LLM config for display: %s", exc)
54
+ cls._llm_info_cache = (now, provider, model_id)
55
+ return provider, model_id
56
+
57
+ @classmethod
58
+ def get_active_model_info(cls, profile: str | None = None) -> dict[str, str]:
59
+ """Return active architecture and underlying LLM model configuration."""
60
+ # 1. Determine underlying LLM model and provider from config (cached)
61
+ provider, model_id = cls._get_llm_provider_and_model()
62
+
63
+ # 2. Determine agent architecture name (Flash vs Pro)
64
+ arch_name = "Flash"
65
+ if profile:
66
+ p_lower = str(profile).lower()
67
+ if "pro" in p_lower:
68
+ arch_name = "Pro"
69
+ elif "flash" in p_lower:
70
+ arch_name = "Flash"
71
+ else:
72
+ arch_name = str(profile).capitalize()
73
+
74
+ return {
75
+ "name": arch_name,
76
+ "id": model_id,
77
+ "provider": provider,
78
+ "architecture": f"ARTEMIS {arch_name}",
79
+ }
80
+
81
+ @staticmethod
82
+ def resolve_session_profile(
83
+ row_dict: dict[str, Any],
84
+ llm_trace_payloads: list[str] | None = None,
85
+ running_profile: str | None = None,
86
+ agent_names: list[str] | None = None,
87
+ ) -> str | None:
88
+ """Resolve the Artemis agent architecture profile ('flash' or 'pro') for a session."""
89
+ sess_profile = None
90
+ d_info_raw = row_dict.get("device_info")
91
+ if d_info_raw:
92
+ try:
93
+ d_info = json.loads(d_info_raw) if isinstance(d_info_raw, str) else d_info_raw
94
+ if isinstance(d_info, dict):
95
+ p = d_info.get("profile")
96
+ if p:
97
+ p_str = str(p).lower()
98
+ if "pro" in p_str:
99
+ return "pro"
100
+ elif "flash" in p_str:
101
+ return "flash"
102
+ except (ValueError, TypeError):
103
+ # Malformed device_info JSON: try the other profile sources.
104
+ pass
105
+
106
+ if (row_dict.get("status") == "running") and running_profile:
107
+ p_str = str(running_profile).lower()
108
+ if "pro" in p_str:
109
+ return "pro"
110
+ elif "flash" in p_str:
111
+ return "flash"
112
+
113
+ # Check Agent/Trace names - the most definitive indicator of architecture
114
+ if agent_names:
115
+ agent_names_lower = [str(a).lower() for a in agent_names]
116
+ if any(
117
+ name in ("planner", "validator", "summarizer", "operator", "checker", "diagnoser")
118
+ for name in agent_names_lower
119
+ ):
120
+ return "pro"
121
+ if any("flashrunner" in name for name in agent_names_lower):
122
+ return "flash"
123
+
124
+ # Check LLM traces for agent name
125
+ if llm_trace_payloads:
126
+ for tr_payload in llm_trace_payloads:
127
+ if tr_payload:
128
+ try:
129
+ p_obj = (
130
+ json.loads(tr_payload) if isinstance(tr_payload, str) else tr_payload
131
+ )
132
+ if isinstance(p_obj, dict):
133
+ agent_name = str(p_obj.get("agent") or p_obj.get("name") or "").lower()
134
+ if "flashrunner" in agent_name:
135
+ return "flash"
136
+ if any(
137
+ x in agent_name
138
+ for x in ("planner", "validator", "operator", "checker")
139
+ ):
140
+ return "pro"
141
+ except (ValueError, TypeError):
142
+ # Malformed trace payload JSON: skip this trace.
143
+ pass
144
+
145
+ return None
146
+
147
+
148
+ model_service = ModelService()
@@ -0,0 +1,514 @@
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
+ """Preset Task Catalog & Dynamic Recommendation Engine for Artemis."""
16
+
17
+ from typing import Any, Literal
18
+ from pydantic import BaseModel, Field
19
+
20
+
21
+ class AppInfo(BaseModel):
22
+ """Application metadata."""
23
+
24
+ name: str
25
+ icon: str
26
+ pkg: str
27
+ category: str = "general"
28
+
29
+
30
+ class TaskPreset(BaseModel):
31
+ """Smart suggestion task definition."""
32
+
33
+ id: str
34
+ title: str
35
+ description: str
36
+ goal: str
37
+ profile: Literal["flash", "pro"]
38
+ category: Literal["flash", "pro", "cross_app", "monitor"]
39
+ tag: str
40
+ apps: list[AppInfo]
41
+ required_packages: list[str] = Field(default_factory=list)
42
+ match_mode: Literal["any", "all"] = "any"
43
+ priority: int = 50
44
+
45
+
46
+ # ============================================================================
47
+ # APP PACKAGE REGISTRY
48
+ # ============================================================================
49
+
50
+ APP_REGISTRY: dict[str, dict[str, str]] = {
51
+ # Google Suite & System
52
+ "com.google.android.apps.maps": {"name": "Maps", "icon": "explore", "category": "navigation"},
53
+ "com.google.android.gm": {"name": "Gmail", "icon": "mail", "category": "productivity"},
54
+ "com.android.chrome": {"name": "Chrome", "icon": "public", "category": "browser"},
55
+ "com.google.android.youtube": {
56
+ "name": "YouTube",
57
+ "icon": "smart_display",
58
+ "category": "entertainment",
59
+ },
60
+ "com.android.settings": {"name": "Settings", "icon": "settings", "category": "system"},
61
+ "com.google.android.deskclock": {"name": "Clock", "icon": "timer", "category": "utility"},
62
+ "com.android.deskclock": {"name": "Clock", "icon": "timer", "category": "utility"},
63
+ "com.google.android.calculator": {
64
+ "name": "Calculator",
65
+ "icon": "calculate",
66
+ "category": "utility",
67
+ },
68
+ "com.android.calculator2": {"name": "Calculator", "icon": "calculate", "category": "utility"},
69
+ "com.google.android.apps.photos": {
70
+ "name": "Photos",
71
+ "icon": "photo_library",
72
+ "category": "media",
73
+ },
74
+ "com.google.android.calendar": {
75
+ "name": "Calendar",
76
+ "icon": "calendar_month",
77
+ "category": "productivity",
78
+ },
79
+ "com.google.android.keep": {
80
+ "name": "Keep Notes",
81
+ "icon": "note_alt",
82
+ "category": "productivity",
83
+ },
84
+ "com.android.vending": {"name": "Play Store", "icon": "storefront", "category": "tools"},
85
+ "com.google.android.apps.messaging": {
86
+ "name": "Messages",
87
+ "icon": "chat",
88
+ "category": "communication",
89
+ },
90
+ # Popular Ecosystem Apps
91
+ "com.tencent.mm": {"name": "WeChat", "icon": "forum", "category": "social"},
92
+ "com.xingin.xhs": {"name": "Xiaohongshu", "icon": "auto_stories", "category": "social"},
93
+ "com.sankuai.meituan": {"name": "Meituan", "icon": "restaurant", "category": "lifestyle"},
94
+ "com.dianping.v1": {"name": "Dianping", "icon": "star", "category": "lifestyle"},
95
+ "tv.danmaku.bili": {"name": "Bilibili", "icon": "video_library", "category": "entertainment"},
96
+ "com.eg.android.AlipayGphone": {
97
+ "name": "Alipay",
98
+ "icon": "account_balance_wallet",
99
+ "category": "finance",
100
+ },
101
+ "com.netease.cloudmusic": {
102
+ "name": "NetEase Music",
103
+ "icon": "headphones",
104
+ "category": "entertainment",
105
+ },
106
+ "com.spotify.music": {"name": "Spotify", "icon": "music_note", "category": "entertainment"},
107
+ }
108
+
109
+
110
+ # ============================================================================
111
+ # CURATED TASK PRESET LIBRARY (1-2 curated tasks per common app)
112
+ # ============================================================================
113
+
114
+ PRESET_TASK_CATALOG: list[TaskPreset] = [
115
+ # 1. Google Maps
116
+ TaskPreset(
117
+ id="maps_coffee",
118
+ title="Find Specialty Coffee",
119
+ description="Search nearby top-rated cafes in Google Maps",
120
+ goal="Open Google Maps, search for top-rated specialty coffee shops nearby, and view the top result details.",
121
+ profile="flash",
122
+ category="flash",
123
+ tag="Maps",
124
+ apps=[
125
+ AppInfo(
126
+ name="Maps",
127
+ icon="explore",
128
+ pkg="com.google.android.apps.maps",
129
+ category="navigation",
130
+ )
131
+ ],
132
+ required_packages=["com.google.android.apps.maps"],
133
+ priority=95,
134
+ ),
135
+ TaskPreset(
136
+ id="pro_commute_share",
137
+ title="Commute ETA & Message Draft",
138
+ description="Check transit time on Maps and draft arrival ETA in Messages",
139
+ goal="Open Google Maps to check commute time to the International Airport, calculate arrival time, then open Messages and draft an ETA text message.",
140
+ profile="pro",
141
+ category="cross_app",
142
+ tag="Maps + Messages",
143
+ apps=[
144
+ AppInfo(
145
+ name="Maps",
146
+ icon="explore",
147
+ pkg="com.google.android.apps.maps",
148
+ category="navigation",
149
+ ),
150
+ AppInfo(
151
+ name="Messages",
152
+ icon="chat",
153
+ pkg="com.google.android.apps.messaging",
154
+ category="communication",
155
+ ),
156
+ ],
157
+ required_packages=["com.google.android.apps.maps", "com.google.android.apps.messaging"],
158
+ match_mode="all",
159
+ priority=92,
160
+ ),
161
+ # 2. Gmail
162
+ TaskPreset(
163
+ id="gmail_receipts",
164
+ title="Search Order Receipts",
165
+ description="Find recent flight or delivery confirmation emails in Gmail",
166
+ goal="Open Gmail and search for recent flight or package delivery confirmation emails.",
167
+ profile="flash",
168
+ category="flash",
169
+ tag="Gmail",
170
+ apps=[
171
+ AppInfo(name="Gmail", icon="mail", pkg="com.google.android.gm", category="productivity")
172
+ ],
173
+ required_packages=["com.google.android.gm"],
174
+ priority=90,
175
+ ),
176
+ TaskPreset(
177
+ id="pro_email_to_calendar",
178
+ title="Email Itinerary to Calendar",
179
+ description="Extract flight or event dates from Gmail and schedule in Calendar",
180
+ goal="Open Gmail to find the latest event invitation or itinerary, extract dates and location, then open Google Calendar and create a corresponding calendar event.",
181
+ profile="pro",
182
+ category="cross_app",
183
+ tag="Gmail + Calendar",
184
+ apps=[
185
+ AppInfo(
186
+ name="Gmail", icon="mail", pkg="com.google.android.gm", category="productivity"
187
+ ),
188
+ AppInfo(
189
+ name="Calendar",
190
+ icon="calendar_month",
191
+ pkg="com.google.android.calendar",
192
+ category="productivity",
193
+ ),
194
+ ],
195
+ required_packages=["com.google.android.gm"],
196
+ priority=94,
197
+ ),
198
+ # 3. Chrome
199
+ TaskPreset(
200
+ id="chrome_research",
201
+ title="Search AI News Breakthroughs",
202
+ description="Search latest multimodal AI developments in Chrome browser",
203
+ goal="Open Chrome browser and search for latest breakthroughs in multimodal mobile AI agents.",
204
+ profile="flash",
205
+ category="flash",
206
+ tag="Chrome",
207
+ apps=[AppInfo(name="Chrome", icon="public", pkg="com.android.chrome", category="browser")],
208
+ required_packages=["com.android.chrome"],
209
+ priority=88,
210
+ ),
211
+ TaskPreset(
212
+ id="pro_research_keep",
213
+ title="Product Research & Notes Note",
214
+ description="Compare top 3 headphones on Chrome and record comparison in Keep",
215
+ goal="Open Chrome, research top 3 noise-cancelling headphones comparing price and battery life, then write a structured comparison summary note in Keep Notes.",
216
+ profile="pro",
217
+ category="pro",
218
+ tag="Chrome + Keep",
219
+ apps=[
220
+ AppInfo(name="Chrome", icon="public", pkg="com.android.chrome", category="browser"),
221
+ AppInfo(
222
+ name="Keep Notes",
223
+ icon="note_alt",
224
+ pkg="com.google.android.keep",
225
+ category="productivity",
226
+ ),
227
+ ],
228
+ required_packages=["com.android.chrome"],
229
+ priority=91,
230
+ ),
231
+ # 4. YouTube
232
+ TaskPreset(
233
+ id="youtube_lofi",
234
+ title="Play Lo-Fi Music Radio",
235
+ description="Search and play a Lo-Fi hip hop live stream on YouTube",
236
+ goal='Open YouTube, search for "Lofi hip hop beats relaxing radio" and tap on the live stream.',
237
+ profile="flash",
238
+ category="flash",
239
+ tag="YouTube",
240
+ apps=[
241
+ AppInfo(
242
+ name="YouTube",
243
+ icon="smart_display",
244
+ pkg="com.google.android.youtube",
245
+ category="entertainment",
246
+ )
247
+ ],
248
+ required_packages=["com.google.android.youtube"],
249
+ priority=85,
250
+ ),
251
+ # 5. Settings
252
+ TaskPreset(
253
+ id="settings_display_wifi",
254
+ title="Dark Mode & Wi-Fi Check",
255
+ description="Toggle dark theme and verify network connection in Settings",
256
+ goal="Open Settings app, navigate to Display settings, ensure Dark theme is enabled, and check Wi-Fi connection status.",
257
+ profile="flash",
258
+ category="flash",
259
+ tag="Settings",
260
+ apps=[
261
+ AppInfo(name="Settings", icon="settings", pkg="com.android.settings", category="system")
262
+ ],
263
+ required_packages=["com.android.settings"],
264
+ priority=87,
265
+ ),
266
+ TaskPreset(
267
+ id="pro_settings_qa",
268
+ title="Subsystem Health & Crash Probe",
269
+ description="Traverse Settings submenus to verify screens and check for crash dialogs",
270
+ goal="Explore Settings submenus (Network, Connected devices, Apps, Battery, Storage), verify each screen loads properly without ANR or crash dialogs, and summarize results.",
271
+ profile="pro",
272
+ category="monitor",
273
+ tag="Settings QA",
274
+ apps=[
275
+ AppInfo(name="Settings", icon="settings", pkg="com.android.settings", category="system")
276
+ ],
277
+ required_packages=["com.android.settings"],
278
+ priority=93,
279
+ ),
280
+ # 6. Clock
281
+ TaskPreset(
282
+ id="clock_timer",
283
+ title="25-Min Pomodoro Timer",
284
+ description="Start a 25-minute focus countdown timer in Clock app",
285
+ goal="Open Clock app, switch to Timer tab, set 25 minutes and start the countdown timer.",
286
+ profile="flash",
287
+ category="flash",
288
+ tag="Clock",
289
+ apps=[
290
+ AppInfo(
291
+ name="Clock", icon="timer", pkg="com.google.android.deskclock", category="utility"
292
+ )
293
+ ],
294
+ required_packages=["com.google.android.deskclock", "com.android.deskclock"],
295
+ priority=86,
296
+ ),
297
+ # 7. Calculator
298
+ TaskPreset(
299
+ id="calc_gratuity",
300
+ title="Split Bill & Calculate Tip",
301
+ description="Calculate 18% gratuity on $186.40 for 3 people in Calculator",
302
+ goal="Open Calculator and calculate 18% tip on a bill of $186.40, then divide by 3 people.",
303
+ profile="flash",
304
+ category="flash",
305
+ tag="Calculator",
306
+ apps=[
307
+ AppInfo(
308
+ name="Calculator",
309
+ icon="calculate",
310
+ pkg="com.google.android.calculator",
311
+ category="utility",
312
+ )
313
+ ],
314
+ required_packages=["com.google.android.calculator", "com.android.calculator2"],
315
+ priority=84,
316
+ ),
317
+ # 8. Photos
318
+ TaskPreset(
319
+ id="photos_inspect",
320
+ title="Inspect Recent Screenshot",
321
+ description="Open Google Photos and review the latest screenshot taken",
322
+ goal="Open Google Photos and view the most recent screenshot in the screenshots album.",
323
+ profile="flash",
324
+ category="flash",
325
+ tag="Photos",
326
+ apps=[
327
+ AppInfo(
328
+ name="Photos",
329
+ icon="photo_library",
330
+ pkg="com.google.android.apps.photos",
331
+ category="media",
332
+ )
333
+ ],
334
+ required_packages=["com.google.android.apps.photos"],
335
+ priority=82,
336
+ ),
337
+ # 9. WeChat
338
+ TaskPreset(
339
+ id="wechat_browse",
340
+ title="Check WeChat Messages",
341
+ description="Open WeChat and view top recent chat conversations",
342
+ goal="Open WeChat and view the top recent chat messages.",
343
+ profile="flash",
344
+ category="flash",
345
+ tag="WeChat",
346
+ apps=[AppInfo(name="WeChat", icon="forum", pkg="com.tencent.mm", category="social")],
347
+ required_packages=["com.tencent.mm"],
348
+ priority=89,
349
+ ),
350
+ TaskPreset(
351
+ id="pro_wechat_to_calendar",
352
+ title="WeChat Notice to Calendar",
353
+ description="Extract meeting notice from WeChat chat and add to Calendar",
354
+ goal="Open WeChat, locate the latest meeting announcement or event message in the top chat, extract the time and topic, then open Calendar and schedule an event.",
355
+ profile="pro",
356
+ category="cross_app",
357
+ tag="WeChat + Calendar",
358
+ apps=[
359
+ AppInfo(name="WeChat", icon="forum", pkg="com.tencent.mm", category="social"),
360
+ AppInfo(
361
+ name="Calendar",
362
+ icon="calendar_month",
363
+ pkg="com.google.android.calendar",
364
+ category="productivity",
365
+ ),
366
+ ],
367
+ required_packages=["com.tencent.mm"],
368
+ priority=93,
369
+ ),
370
+ # 10. Xiaohongshu
371
+ TaskPreset(
372
+ id="xhs_coffee_guide",
373
+ title="RED Cafe Guide Search",
374
+ description="Search trending specialty cafe reviews on Xiaohongshu",
375
+ goal="Open Xiaohongshu, search for top-rated specialty coffee shops, and view the top post.",
376
+ profile="flash",
377
+ category="flash",
378
+ tag="Xiaohongshu",
379
+ apps=[
380
+ AppInfo(
381
+ name="Xiaohongshu", icon="auto_stories", pkg="com.xingin.xhs", category="social"
382
+ )
383
+ ],
384
+ required_packages=["com.xingin.xhs"],
385
+ priority=87,
386
+ ),
387
+ # 11. Meituan / Dianping
388
+ TaskPreset(
389
+ id="meituan_ramen_search",
390
+ title="Meituan Food Search",
391
+ description="Search top-rated Ramen nearby on Meituan or Dianping",
392
+ goal="Open Meituan or Dianping, search for top-rated Ramen nearby, and view top restaurant rating.",
393
+ profile="flash",
394
+ category="flash",
395
+ tag="Meituan",
396
+ apps=[
397
+ AppInfo(
398
+ name="Meituan", icon="restaurant", pkg="com.sankuai.meituan", category="lifestyle"
399
+ )
400
+ ],
401
+ required_packages=["com.sankuai.meituan", "com.dianping.v1"],
402
+ priority=86,
403
+ ),
404
+ # 12. Bilibili
405
+ TaskPreset(
406
+ id="bilibili_stream",
407
+ title="Bilibili Tech Video",
408
+ description="Search and play an AI Agent tutorial video on Bilibili",
409
+ goal='Open Bilibili, search for "AI Agent Architecture", and play the top matching video.',
410
+ profile="flash",
411
+ category="flash",
412
+ tag="Bilibili",
413
+ apps=[
414
+ AppInfo(
415
+ name="Bilibili",
416
+ icon="video_library",
417
+ pkg="tv.danmaku.bili",
418
+ category="entertainment",
419
+ )
420
+ ],
421
+ required_packages=["tv.danmaku.bili"],
422
+ priority=85,
423
+ ),
424
+ # 13. Play Store
425
+ TaskPreset(
426
+ id="pro_playstore_review",
427
+ title="Play Store App Review Study",
428
+ description="Compare top task management apps and ratings on Google Play",
429
+ goal="Open Google Play Store, search for top rated task management apps, compare ratings and latest user reviews of the top 2 candidates, and record recommendations.",
430
+ profile="pro",
431
+ category="pro",
432
+ tag="Play Store",
433
+ apps=[
434
+ AppInfo(
435
+ name="Play Store", icon="storefront", pkg="com.android.vending", category="tools"
436
+ )
437
+ ],
438
+ required_packages=["com.android.vending"],
439
+ priority=88,
440
+ ),
441
+ ]
442
+
443
+
444
+ # ============================================================================
445
+ # RECOMMENDATION ENGINE
446
+ # ============================================================================
447
+
448
+
449
+ class TaskRecommendationEngine:
450
+ """Intelligent recommendation engine matching device capabilities."""
451
+
452
+ def __init__(self, catalog: list[TaskPreset] | None = None):
453
+ self.catalog = catalog or PRESET_TASK_CATALOG
454
+
455
+ def get_all_tasks(self) -> list[dict[str, Any]]:
456
+ return [task.model_dump() for task in self.catalog]
457
+
458
+ def recommend_tasks(
459
+ self, installed_packages: list[str] | set[str], category: str = "all", limit: int = 12
460
+ ) -> list[dict[str, Any]]:
461
+ pkgs_set = (
462
+ set(installed_packages) if isinstance(installed_packages, list) else installed_packages
463
+ )
464
+
465
+ scored_tasks: list[tuple[int, TaskPreset, bool]] = []
466
+
467
+ for task in self.catalog:
468
+ # Check package presence
469
+ is_matched = False
470
+ if pkgs_set:
471
+ if not task.required_packages:
472
+ is_matched = True
473
+ elif task.match_mode == "all":
474
+ is_matched = all(pkg in pkgs_set for pkg in task.required_packages)
475
+ else:
476
+ is_matched = any(pkg in pkgs_set for pkg in task.required_packages)
477
+ else:
478
+ is_matched = False
479
+
480
+ # Calculate score
481
+ score = task.priority
482
+ if pkgs_set:
483
+ if is_matched:
484
+ score += 100
485
+ if len(task.required_packages) > 1 and task.match_mode == "all":
486
+ score += 30
487
+ else:
488
+ score -= 40
489
+
490
+ # Filter by category
491
+ if category == "flash" and task.profile != "flash":
492
+ continue
493
+ elif category == "pro" and task.profile != "pro":
494
+ continue
495
+ elif category == "cross_app" and task.category != "cross_app":
496
+ continue
497
+ elif category == "monitor" and task.category != "monitor":
498
+ continue
499
+
500
+ scored_tasks.append((score, task, is_matched))
501
+
502
+ # Sort descending by score
503
+ scored_tasks.sort(key=lambda item: item[0], reverse=True)
504
+
505
+ results: list[dict[str, Any]] = []
506
+ for _, task, matched in scored_tasks[:limit]:
507
+ d = task.model_dump()
508
+ d["is_device_matched"] = matched
509
+ results.append(d)
510
+
511
+ return results
512
+
513
+
514
+ task_recommendation_engine = TaskRecommendationEngine()