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,182 @@
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
+ """History Analyzer: answers natural-language questions about the session history.
16
+
17
+ Mounts the shared history tools (``search_history`` / ``replay_steps`` /
18
+ ``get_step_screenshot``) plus the read-only note tools; tool results enter the
19
+ conversation through ``tool_result_messages`` so a fetched screenshot travels
20
+ in the carrier the model's provider accepts.
21
+ """
22
+
23
+ from pathlib import Path
24
+
25
+ from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
26
+ from langchain_core.tools import BaseTool
27
+
28
+ from artemis.core.tool_failure import is_tool_failure
29
+ from artemis.context import ArtemisContext
30
+ from artemis.data_engine.trace import TraceSpan, trace
31
+ from artemis.memory.context_policy import build_history_for
32
+ from artemis.services.llm import acomplete, get_llm, invoke_llm_with_timeout_message
33
+ from artemis.tools.history import get_history_tools
34
+ from artemis.tools.scratchpad import (
35
+ get_list_notes_tool_pure,
36
+ get_read_note_tool_pure,
37
+ )
38
+ from artemis.tools.tool_wrapper import (
39
+ invoke_tool_with_injection,
40
+ split_multimodal_result,
41
+ tool_result_messages,
42
+ )
43
+ from artemis.utils.notes import get_note_file_path
44
+ from artemis.utils.task_tree import get_active_subgoal_hashes
45
+ from third_party.mobile_use.utils.logger import get_logger
46
+
47
+ logger = get_logger(__name__)
48
+
49
+ _FALLBACK_SYSTEM_PROMPT = (
50
+ "You are a History Analyzer. Your role is to analyze the execution history"
51
+ " of a session and answer user queries in natural language.\nIf you need"
52
+ " the full record of specific steps, use the `replay_steps` tool; use"
53
+ " `search_history` to locate steps by keyword and `get_step_screenshot` to"
54
+ " look at a step's screen."
55
+ )
56
+
57
+
58
+ class HistoryAnalyzer:
59
+ def __init__(self, ctx: ArtemisContext):
60
+ self.ctx = ctx
61
+
62
+ def _build_tools(self) -> list[BaseTool]:
63
+ return [
64
+ *get_history_tools(self.ctx),
65
+ get_list_notes_tool_pure(self.ctx),
66
+ get_read_note_tool_pure(self.ctx),
67
+ ]
68
+
69
+ @trace(type="agent", name="history_analyzer")
70
+ async def run(self, query: str) -> str:
71
+ if not self.ctx.data_engine:
72
+ return "Error: DataEngine is not available to retrieve history."
73
+
74
+ # 1. Fetch all steps from Data Engine
75
+ history_steps = self.ctx.data_engine.get_agent_friendly_steps()
76
+ if not history_steps:
77
+ return "No history recorded for this session yet."
78
+
79
+ # 2. Build the plan and history or step list
80
+ plan_and_history = ""
81
+ try:
82
+ current_plan = ""
83
+ current_path = get_note_file_path(self.ctx.data_engine.base_dir, "task_plan")
84
+ if current_path.exists():
85
+ current_plan = current_path.read_text(encoding="utf-8")
86
+
87
+ if current_plan:
88
+ active_subgoal_hash, _ = get_active_subgoal_hashes(current_plan)
89
+ plan_and_history = build_history_for(
90
+ "history_analyzer",
91
+ current_plan,
92
+ history_steps,
93
+ active_subgoal_hash,
94
+ engine=self.ctx.data_engine,
95
+ )
96
+ except Exception as e:
97
+ logger.error(f"Failed to build plan and history in HistoryAnalyzer: {e}")
98
+
99
+ if not plan_and_history:
100
+ # Fallback to a simple list
101
+ plan_and_history = "\n".join(
102
+ [
103
+ f"- Step {s.get('step_number')} ({s.get('relative_time')}):"
104
+ f" {s.get('summary') or 'No summary'}"
105
+ for s in history_steps
106
+ ]
107
+ )
108
+
109
+ # 3. Load system prompt
110
+ prompt_path = Path(__file__).parent.joinpath("history_analyzer.md")
111
+ if prompt_path.exists():
112
+ system_prompt_template = prompt_path.read_text(encoding="utf-8")
113
+ else:
114
+ system_prompt_template = _FALLBACK_SYSTEM_PROMPT
115
+
116
+ system_message_content = (
117
+ system_prompt_template + f"\n\n### Task Plan and Execution History:\n{plan_and_history}"
118
+ )
119
+
120
+ # 4. Prepare LLM and bind tools
121
+ llm = get_llm(ctx=self.ctx, name="history_analyzer")
122
+ tools = self._build_tools()
123
+ llm = llm.bind_tools(tools=tools)
124
+
125
+ # 5. ReAct Loop
126
+ messages: list[BaseMessage] = [
127
+ SystemMessage(content=system_message_content),
128
+ HumanMessage(content=query),
129
+ ]
130
+
131
+ max_turns = 5
132
+ for turn in range(max_turns):
133
+ logger.info(f"HistoryAnalyzer ReAct turn {turn + 1}")
134
+
135
+ response = await invoke_llm_with_timeout_message(acomplete(llm, messages))
136
+ messages.append(response)
137
+
138
+ if not response.tool_calls:
139
+ return (
140
+ response.content.strip()
141
+ if isinstance(response.content, str)
142
+ else str(response.content)
143
+ )
144
+
145
+ # Process tool calls
146
+ for tc in response.tool_calls:
147
+ tool_name = tc["name"].split(":")[-1] if ":" in tc["name"] else tc["name"]
148
+ args = dict(tc.get("args") or {})
149
+ tool = next((t for t in tools if t.name == tool_name), None)
150
+
151
+ with TraceSpan(name=tool_name, ctx=self.ctx) as span:
152
+ span.payload = {"args": args}
153
+ if tool is None:
154
+ result = f"Error: Tool {tool_name} is not supported."
155
+ status = "error"
156
+ span.status = "failed"
157
+ span.error = result
158
+ else:
159
+ logger.info(f"HistoryAnalyzer executing tool {tool_name} with args: {args}")
160
+ try:
161
+ result = await invoke_tool_with_injection(
162
+ tool=tool, args=args, tool_call_id=tc["id"]
163
+ )
164
+ text, _ = split_multimodal_result(result)
165
+ status = "error" if is_tool_failure(result) else "success"
166
+ span.result = text
167
+ if status == "error":
168
+ span.status = "failed"
169
+ span.error = text
170
+ except Exception as e:
171
+ span.status = "failed"
172
+ span.error = str(e)
173
+ result = f"Error running {tool_name}: {e}"
174
+ status = "error"
175
+
176
+ # A step screenshot travels in the carrier the model's provider
177
+ # accepts; text results stay a single ToolMessage.
178
+ messages.extend(
179
+ tool_result_messages(tc["id"], result, name=tool_name, status=status, llm=llm)
180
+ )
181
+
182
+ return "Error: HistoryAnalyzer failed to resolve the query within maximum turns."
@@ -0,0 +1,74 @@
1
+ # IDENTITY
2
+ You are the expert UI Image Processor, a coding agent that can write Python scripts to analyze and modify images (like color filtering, cropping, highlighting, coloring, or performing custom image processing).
3
+
4
+ # CONTEXT
5
+ Target Image ID: `img_0` (This is the original input screenshot)
6
+ Instruction: {instruction}
7
+ Intermediate Artifact Save Path: `{intermediate_artifact_save_path}`
8
+ If you want to save intermediate steps to inspect them or load them later, you must call `canvas.save(final=False)`. Any intermediate images saved this way will be automatically loaded and fed back to you as visual context at the beginning of your next turn, and can be retrieved in subsequent runs by instantiating a new canvas: `ImageCanvas(image_id, '{intermediate_artifact_save_path}')`.
9
+
10
+
11
+ # GOAL
12
+ Your goal is to perform image analysis, filter, crop, draw annotations/markers, or modify the image to visually highlight or isolate specific features as requested. Write a Python script using OpenCV (`cv2`), `numpy`, or other standard libraries to analyze and modify the target image `img_0` according to the `Instruction`. The final output should be the modified image. Call `submit_result` tool after you have successfully completed the task.
13
+
14
+ # CRITICAL BOUNDARIES FOR GEOMETRIC TRANSFORMATIONS
15
+ 1. **DO NOT** use numpy array slicing (e.g. `img[y:y+h, x:x+w]`) to crop the image.
16
+ 2. **DO NOT** use `cv2.resize()` to scale the image.
17
+ Our system performs strict syntax validation; using the above will crash your execution.
18
+
19
+ If you MUST crop or scale the image to isolate small details or improve reading/detection downstream, you MUST use the pre-imported `ImageCanvas` tool exactly as follows:
20
+
21
+ ### Snippet 1: Saving & Resuming Intermediate Steps (Iterative Workflow)
22
+ Use this to crop/zoom into specific areas and save them so you can visually inspect them in your next turn, or load them back to create new branches.
23
+ ```python
24
+ from artemis.utils.cv_canvas import ImageCanvas
25
+
26
+ # 1. Start from the original image:
27
+ canvas = ImageCanvas("img_0", "{intermediate_artifact_save_path}")
28
+
29
+ # 2. Crop and scale:
30
+ canvas.crop(x=100, y=200, w=300, h=300)
31
+ canvas.resize_by_factor(2.0)
32
+
33
+ # 3. Save as an intermediate step for verification:
34
+ # This will auto-generate 'img_1' and save it in the intermediate directory.
35
+ # In the next turn, you will receive 'img_1' as visual confirmation.
36
+ canvas.save(final=False)
37
+
38
+ # --- In a subsequent turn, if you want to resume from 'img_1' ---
39
+ # canvas = ImageCanvas('img_1', '{intermediate_artifact_save_path}')
40
+ ```
41
+
42
+ ### Snippet 2: Finalizing and Saving the Output
43
+ Use this to draw your final annotations, highlights, or markers, and save the final result to be returned.
44
+ ```python
45
+ from artemis.utils.cv_canvas import ImageCanvas
46
+
47
+ # 1. Load the original or a cropped intermediate step to finalize:
48
+ canvas = ImageCanvas("img_1", "{intermediate_artifact_save_path}")
49
+
50
+ # 2. Draw annotations, highlight elements, or apply filters:
51
+ # # Convert normalized coordinates (0-1000) to pixel coordinates:
52
+ # x, y = canvas.normalized_to_pixel_coords(nx, ny)
53
+ # Draw specific verification dots and register their labels with unique label_idx (e.g. V1):
54
+ # canvas.draw_dot(100, 200, 1)
55
+
56
+ # 3. Save the final result (this is required to complete the task):
57
+ # This will auto-generate the next sequential image ID (e.g., 'img_2') and mark it as a final output.
58
+ canvas.save(final=True)
59
+ ```
60
+
61
+ ### Snippet 3: Simple Modification Without Cropping or Scaling
62
+ If you do NOT need to crop or scale, but just want to draw annotations or apply filters, you can still use `ImageCanvas` for consistency:
63
+ ```python
64
+ from artemis.utils.cv_canvas import ImageCanvas
65
+
66
+ canvas = ImageCanvas("img_0", "{intermediate_artifact_save_path}")
67
+ # ... modify canvas.img ...
68
+ canvas.save(final=True)
69
+ ```
70
+
71
+ # EXECUTION LOOP
72
+ 1. Write and execute your script using the `execute_python` tool.
73
+ 2. Read the stdout/stderr. If there are errors, fix your code and execute again.
74
+ 3. Once you have successfully called `canvas.save(final=True)` on your final output image(s), call the `submit_result` tool with a summary to finish your job.
@@ -0,0 +1,322 @@
1
+ # Copyright 2026 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Universal Multi-Model Image Processor for Artemis."""
16
+
17
+ import base64
18
+ import json
19
+ from pathlib import Path
20
+ import shutil
21
+ import time
22
+ import uuid
23
+
24
+ from langchain_core.messages import (
25
+ BaseMessage,
26
+ HumanMessage,
27
+ SystemMessage,
28
+ ToolMessage,
29
+ )
30
+
31
+ from artemis.config import settings
32
+ from artemis.context import ArtemisContext
33
+ from artemis.core.tool_declaration import ToolDeclaration
34
+ from artemis.data_engine.trace import TraceSpan, trace
35
+ from artemis.services.llm import get_llm
36
+ from artemis.utils.python_executor import PythonExecutor
37
+ from third_party.mobile_use.utils.logger import get_logger
38
+
39
+ logger = get_logger(__name__)
40
+
41
+ EXECUTE_PYTHON_TOOL = ToolDeclaration(
42
+ name="execute_python",
43
+ description=(
44
+ "Executes the provided Python code within an isolated"
45
+ " Jupyter environment and returns the resulting stdout,"
46
+ " stderr, and traceback outputs."
47
+ ),
48
+ parameters={
49
+ "type": "object",
50
+ "properties": {
51
+ "code": {
52
+ "type": "string",
53
+ "description": "The Python code to execute",
54
+ }
55
+ },
56
+ "required": ["code"],
57
+ },
58
+ )
59
+
60
+ SUBMIT_RESULT_TOOL = ToolDeclaration(
61
+ name="submit_result",
62
+ description=("Submits a summary of the modifications to successfully complete the task."),
63
+ parameters={
64
+ "type": "object",
65
+ "properties": {
66
+ "summary": {
67
+ "type": "string",
68
+ "description": "Summary of what you found or changed.",
69
+ }
70
+ },
71
+ "required": ["summary"],
72
+ },
73
+ )
74
+
75
+
76
+ class ImageProcessor:
77
+ def __init__(self, ctx: ArtemisContext):
78
+ self.ctx = ctx
79
+
80
+ @trace(type="agent", name="image_processor")
81
+ async def run(self, instruction: str, target_image_path: str) -> dict:
82
+ try:
83
+ llm = get_llm(self.ctx, name="image_processor")
84
+ except Exception:
85
+ llm = get_llm(self.ctx, name="operator")
86
+
87
+ base_dir = settings.TRACES_PATH
88
+ image_processor_dir = base_dir / "images" / "image_processor"
89
+ image_processor_dir.mkdir(parents=True, exist_ok=True)
90
+ intermediate_artifact_save_path = image_processor_dir / f"intermediates_{int(time.time())}"
91
+ intermediate_artifact_save_path.mkdir(parents=True, exist_ok=True)
92
+ intermediate_artifact_save_path_str = str(intermediate_artifact_save_path.resolve())
93
+
94
+ max_iterations = 5
95
+
96
+ prompt_path = Path(__file__).parent / "image_processor.md"
97
+ prompt_template = prompt_path.read_text(encoding="utf-8")
98
+ prompt_template = (
99
+ prompt_template.replace("{target_image_path}", target_image_path)
100
+ .replace("{instruction}", instruction)
101
+ .replace(
102
+ "{intermediate_artifact_save_path}",
103
+ intermediate_artifact_save_path_str,
104
+ )
105
+ .replace("{max_iterations}", str(max_iterations))
106
+ )
107
+
108
+ tools_declaration = [EXECUTE_PYTHON_TOOL, SUBMIT_RESULT_TOOL]
109
+
110
+ with open(target_image_path, "rb") as f:
111
+ img_bytes = f.read()
112
+ img_b64 = base64.b64encode(img_bytes).decode("utf-8")
113
+
114
+ messages: list[BaseMessage] = [
115
+ SystemMessage(content=prompt_template),
116
+ HumanMessage(
117
+ content=[
118
+ {"type": "text", "text": "Here is the target image. Begin writing your code."},
119
+ {
120
+ "type": "image_url",
121
+ "image_url": {"url": f"data:image/jpeg;base64,{img_b64}"},
122
+ },
123
+ ]
124
+ ),
125
+ ]
126
+
127
+ img_0_path = intermediate_artifact_save_path / "img_0.jpg"
128
+ try:
129
+ shutil.copy2(target_image_path, img_0_path)
130
+ except Exception as e:
131
+ logger.error(f"Failed to copy original screenshot to intermediate pool: {e}")
132
+ img_0_path = Path(target_image_path)
133
+
134
+ self.intermediate_image_pool = {
135
+ "img_0": {
136
+ "image_id": "img_0",
137
+ "path": str(img_0_path.resolve()),
138
+ "turn_id": 0,
139
+ "transform": {
140
+ "offset_x": 0.0,
141
+ "offset_y": 0.0,
142
+ "scale_x": 1.0,
143
+ "scale_y": 1.0,
144
+ },
145
+ "annotations": {},
146
+ }
147
+ }
148
+
149
+ pool_json_path = intermediate_artifact_save_path / "intermediate_transforms.json"
150
+ sync_pool = {
151
+ "img_0": {
152
+ "image_id": "img_0",
153
+ "path": self.intermediate_image_pool["img_0"]["path"],
154
+ "transform": self.intermediate_image_pool["img_0"]["transform"],
155
+ "annotations": {},
156
+ }
157
+ }
158
+ with open(pool_json_path, "w") as f:
159
+ json.dump(sync_pool, f)
160
+
161
+ executor = PythonExecutor(session_dir=image_processor_dir)
162
+ iterations = 0
163
+ final_result = None
164
+
165
+ try:
166
+ while iterations < max_iterations:
167
+ iterations += 1
168
+ logger.info(f"ImageProcessor Iteration {iterations}")
169
+
170
+ # Inject newly created intermediate images from last turn
171
+ if self.intermediate_image_pool:
172
+ image_blocks = []
173
+ last_turn_id = iterations - 1
174
+ for img_id, entry in self.intermediate_image_pool.items():
175
+ if entry["turn_id"] == last_turn_id:
176
+ try:
177
+ path = Path(entry["path"])
178
+ if path.exists():
179
+ b64_data = base64.b64encode(path.read_bytes()).decode("utf-8")
180
+ is_output = entry.get("is_output", False)
181
+ label = (
182
+ f"img_id: {img_id} (Output)"
183
+ if is_output
184
+ else f"img_id: {img_id}"
185
+ )
186
+ image_blocks.append(
187
+ {
188
+ "type": "image_url",
189
+ "image_url": {
190
+ "url": f"data:image/jpeg;base64,{b64_data}"
191
+ },
192
+ }
193
+ )
194
+ image_blocks.append({"type": "text", "text": f"\n{label}\n"})
195
+ except Exception as e:
196
+ logger.error(
197
+ f"Failed to read intermediate image {entry['path']}: {e}"
198
+ )
199
+
200
+ if image_blocks:
201
+ if (
202
+ messages
203
+ and isinstance(messages[-1], HumanMessage)
204
+ and isinstance(messages[-1].content, list)
205
+ ):
206
+ messages[-1].content.extend(image_blocks)
207
+ else:
208
+ messages.append(HumanMessage(content=image_blocks))
209
+
210
+ if iterations == max_iterations - 1:
211
+ warning_msg = (
212
+ "\n[WARNING] This is your next-to-last iteration. You"
213
+ " must complete your task and call `submit_result` now"
214
+ " or in the next turn, as no further code execution"
215
+ " will be allowed after that."
216
+ )
217
+ messages.append(HumanMessage(content=warning_msg))
218
+ elif iterations == max_iterations:
219
+ warning_msg = (
220
+ "\n[WARNING] This is your final iteration. You MUST"
221
+ " call `submit_result` now to complete the task. No"
222
+ " other tools are available."
223
+ )
224
+ messages.append(HumanMessage(content=warning_msg))
225
+
226
+ current_tools = tools_declaration
227
+ if iterations == max_iterations:
228
+ current_tools = [t for t in tools_declaration if t.name == "submit_result"]
229
+
230
+ bound_llm = llm.bind_tools(current_tools)
231
+
232
+ with TraceSpan(name="image_processor_call", ctx=self.ctx):
233
+ response = await bound_llm.ainvoke(messages)
234
+
235
+ tool_calls = response.tool_calls or []
236
+ if not tool_calls:
237
+ break
238
+
239
+ messages.append(response)
240
+
241
+ submit_called = False
242
+ for tc in tool_calls:
243
+ name = tc["name"].split(":")[-1] if ":" in tc["name"] else tc["name"]
244
+ args = tc.get("args") or {}
245
+ tc_id = tc.get("id") or str(uuid.uuid4())
246
+
247
+ if name == "submit_result":
248
+ final_result = args
249
+ submit_called = True
250
+ messages.append(
251
+ ToolMessage(
252
+ tool_call_id=tc_id,
253
+ name=name,
254
+ content=json.dumps({"status": "submitted"}),
255
+ status="success",
256
+ )
257
+ )
258
+ break
259
+
260
+ elif name == "execute_python":
261
+ code = args.get("code", "")
262
+ logger.info("Executing Python code via PythonExecutor")
263
+ exec_output = executor.execute(code)
264
+
265
+ messages.append(
266
+ ToolMessage(
267
+ tool_call_id=tc_id,
268
+ name=name,
269
+ content=exec_output,
270
+ status="success",
271
+ )
272
+ )
273
+
274
+ if pool_json_path.exists():
275
+ try:
276
+ with open(pool_json_path) as f:
277
+ loaded_pool = json.load(f)
278
+ for img_id, entry in loaded_pool.items():
279
+ if img_id not in self.intermediate_image_pool:
280
+ self.intermediate_image_pool[img_id] = {
281
+ "image_id": img_id,
282
+ "path": entry["path"],
283
+ "turn_id": iterations,
284
+ "transform": entry["transform"],
285
+ "is_output": entry.get("is_output", False),
286
+ "annotations": entry.get("annotations", {}),
287
+ }
288
+ except Exception as e:
289
+ logger.error(f"Failed to read pool_json_path: {e}")
290
+
291
+ if submit_called:
292
+ break
293
+
294
+ finally:
295
+ executor.close()
296
+
297
+ outputs = [
298
+ entry
299
+ for entry in self.intermediate_image_pool.values()
300
+ if entry.get("is_output") is True
301
+ ]
302
+
303
+ if not outputs:
304
+ sorted_keys = sorted(
305
+ self.intermediate_image_pool.keys(),
306
+ key=lambda k: (
307
+ int(k.split("_")[1])
308
+ if k.startswith("img_") and k.split("_")[1].isdigit()
309
+ else -1
310
+ ),
311
+ )
312
+ if sorted_keys:
313
+ last_key = sorted_keys[-1]
314
+ outputs = [self.intermediate_image_pool[last_key]]
315
+
316
+ summary = (
317
+ final_result.get("summary", "")
318
+ if final_result
319
+ else "Failed to submit result within iterations"
320
+ )
321
+
322
+ return {"outputs": outputs, "summary": summary}
@@ -0,0 +1,15 @@
1
+ # Log Analysis Instructions
2
+
3
+ You are the Log Analyzer Agent, responsible for diagnosing issues by querying Android device logs.
4
+ Your primary goal is to find errors or specific events efficiently without exhausting system resources.
5
+
6
+ ## Core Strategy: Separation of Search and Read (Grep-like Behavior)
7
+ You MUST avoid reading massive chunks of logs. Instead, use a "Grep-then-Read" approach:
8
+ 1. **Precision Search (Grep)**: Always start by using `search_logs` with `context_lines=0`. Search for specific keywords, package names (e.g., `net.osmand`), or Exception tags. This will return the exact line numbers and timestamps of the events.
9
+ 2. **Targeted Reading (Read)**: Once you find a highly relevant match from your search (e.g., an error stack trace start), use `read_logs` and specify the `since_time` and `until_time` to fetch ONLY the small 20-50 line window around that exact event.
10
+
11
+ ## Guidelines
12
+ 1. **Efficiency**: Never call `search_logs` with `context_lines` > 5 unless you are absolutely sure there are very few matches. Large context windows will cause the system to truncate your output and you will lose data.
13
+ 2. **Unknown Errors**: Use `google_search` for unfamiliar error codes or system tags.
14
+ 3. **Handling Missing Data**: If you have executed several searches and cannot find any matching logs, DO NOT loop indefinitely. Return a final summary stating that no logs matching the criteria were found.
15
+ 4. **Response Format**: You should provide your final log analysis in one paragraph. You can organize it into clear, concise parts (e.g., Search Results, Analysis, Key Events, and more). You should include all helpful technical details (e.g. original logs, timestamps, and more).