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.
- package/CHANGELOG.md +10 -0
- package/README.md +159 -29
- package/artemis-main/.dockerignore +15 -0
- package/artemis-main/.env.example +34 -0
- package/artemis-main/CONTRIBUTING.md +35 -0
- package/artemis-main/Dockerfile +68 -0
- package/artemis-main/LICENSE +202 -0
- package/artemis-main/Makefile +115 -0
- package/artemis-main/README.md +322 -0
- package/artemis-main/README_CN.md +320 -0
- package/artemis-main/apps/__init__.py +15 -0
- package/artemis-main/apps/admin_console/__init__.py +19 -0
- package/artemis-main/apps/admin_console/core/__init__.py +13 -0
- package/artemis-main/apps/admin_console/core/config.py +43 -0
- package/artemis-main/apps/admin_console/core/security.py +178 -0
- package/artemis-main/apps/admin_console/core/state.py +243 -0
- package/artemis-main/apps/admin_console/database/__init__.py +13 -0
- package/artemis-main/apps/admin_console/database/connection.py +60 -0
- package/artemis-main/apps/admin_console/database/repositories/__init__.py +13 -0
- package/artemis-main/apps/admin_console/database/repositories/session_repository.py +564 -0
- package/artemis-main/apps/admin_console/database/repositories/step_repository.py +512 -0
- package/artemis-main/apps/admin_console/database/repositories/trace_repository.py +133 -0
- package/artemis-main/apps/admin_console/index.html +3787 -0
- package/artemis-main/apps/admin_console/replay_manager.py +2585 -0
- package/artemis-main/apps/admin_console/routers/__init__.py +13 -0
- package/artemis-main/apps/admin_console/routers/media.py +198 -0
- package/artemis-main/apps/admin_console/routers/replay.py +91 -0
- package/artemis-main/apps/admin_console/routers/sessions.py +239 -0
- package/artemis-main/apps/admin_console/routers/steps.py +109 -0
- package/artemis-main/apps/admin_console/routers/stream.py +56 -0
- package/artemis-main/apps/admin_console/routers/system.py +761 -0
- package/artemis-main/apps/admin_console/routers/tasks.py +517 -0
- package/artemis-main/apps/admin_console/schemas/__init__.py +13 -0
- package/artemis-main/apps/admin_console/schemas/task_schema.py +47 -0
- package/artemis-main/apps/admin_console/server.py +508 -0
- package/artemis-main/apps/admin_console/services/__init__.py +13 -0
- package/artemis-main/apps/admin_console/services/device_stream_service.py +137 -0
- package/artemis-main/apps/admin_console/services/ipc_service.py +262 -0
- package/artemis-main/apps/admin_console/services/media_service.py +623 -0
- package/artemis-main/apps/admin_console/services/model_service.py +148 -0
- package/artemis-main/apps/admin_console/services/task_preset_catalog.py +514 -0
- package/artemis-main/apps/admin_console/services/task_queue_service.py +1719 -0
- package/artemis-main/apps/admin_console/services/worker_process_io.py +144 -0
- package/artemis-main/apps/showcase_ui/README.md +31 -0
- package/artemis-main/apps/showcase_ui/angular.json +132 -0
- package/artemis-main/apps/showcase_ui/package-lock.json +9472 -0
- package/artemis-main/apps/showcase_ui/package.json +39 -0
- package/artemis-main/apps/showcase_ui/proxy.conf.json +23 -0
- package/artemis-main/apps/showcase_ui/public/favicon.ico +0 -0
- package/artemis-main/apps/showcase_ui/public/logo.png +0 -0
- package/artemis-main/apps/showcase_ui/public/logo.svg +56 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.html +24 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.scss +49 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.spec.ts +42 -0
- package/artemis-main/apps/showcase_ui/src/app/app.component.ts +32 -0
- package/artemis-main/apps/showcase_ui/src/app/app.config.ts +29 -0
- package/artemis-main/apps/showcase_ui/src/app/app.routes.ts +27 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream-startup.spec.ts +108 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html +1436 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.scss +3973 -0
- package/artemis-main/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.ts +2235 -0
- package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.html +380 -0
- package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.scss +1171 -0
- package/artemis-main/apps/showcase_ui/src/app/components/chat-interface/chat-interface.component.ts +270 -0
- package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.html +433 -0
- package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.scss +987 -0
- package/artemis-main/apps/showcase_ui/src/app/components/floating-video-player/floating-video-player.component.ts +632 -0
- package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.html +130 -0
- package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.scss +406 -0
- package/artemis-main/apps/showcase_ui/src/app/components/legacy-agent-stream/legacy-agent-stream.component.ts +74 -0
- package/artemis-main/apps/showcase_ui/src/app/components/nav-switcher/nav-switcher.component.scss +115 -0
- package/artemis-main/apps/showcase_ui/src/app/components/nav-switcher/nav-switcher.component.ts +52 -0
- package/artemis-main/apps/showcase_ui/src/app/core/data/smart-tasks.data.ts +334 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/language.service.spec.ts +55 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/language.service.ts +61 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/translate.pipe.ts +11 -0
- package/artemis-main/apps/showcase_ui/src/app/core/i18n/zh-cn.ts +651 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/markdown.model.ts +43 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/pro-tuning.model.spec.ts +47 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/pro-tuning.model.ts +165 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/session.model.ts +85 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/stream.model.ts +246 -0
- package/artemis-main/apps/showcase_ui/src/app/core/models/system.model.ts +118 -0
- package/artemis-main/apps/showcase_ui/src/app/core/services/task-recommendation.service.ts +111 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.html +2130 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.scss +5204 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/home/home.component.ts +1189 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.html +39 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.scss +151 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/legacy-workspace/legacy-workspace.component.ts +58 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.html +201 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.scss +886 -0
- package/artemis-main/apps/showcase_ui/src/app/pages/workspace/workspace.component.ts +324 -0
- package/artemis-main/apps/showcase_ui/src/app/services/agent.service.spec.ts +418 -0
- package/artemis-main/apps/showcase_ui/src/app/services/agent.service.ts +2012 -0
- package/artemis-main/apps/showcase_ui/src/app/services/system.service.spec.ts +173 -0
- package/artemis-main/apps/showcase_ui/src/app/services/system.service.ts +620 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/action-formatter.util.spec.ts +513 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/action-formatter.util.ts +1015 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/image-overlay.util.spec.ts +85 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/image-overlay.util.ts +662 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/markdown-parser.util.spec.ts +70 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/markdown-parser.util.ts +383 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/recording-timeline.util.spec.ts +107 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/recording-timeline.util.ts +123 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/run-info.util.spec.ts +92 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/run-info.util.ts +116 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/stream-aggregator.util.spec.ts +640 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/stream-aggregator.util.ts +1021 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/tool-formatter.util.spec.ts +375 -0
- package/artemis-main/apps/showcase_ui/src/app/utils/tool-formatter.util.ts +1419 -0
- package/artemis-main/apps/showcase_ui/src/index.html +37 -0
- package/artemis-main/apps/showcase_ui/src/main.ts +22 -0
- package/artemis-main/apps/showcase_ui/src/styles.scss +60 -0
- package/artemis-main/apps/showcase_ui/tsconfig.app.json +23 -0
- package/artemis-main/apps/showcase_ui/tsconfig.json +27 -0
- package/artemis-main/apps/showcase_ui/tsconfig.spec.json +23 -0
- package/artemis-main/artemis/__init__.py +44 -0
- package/artemis-main/artemis/__main__.py +18 -0
- package/artemis-main/artemis/_legacy_imports.py +94 -0
- package/artemis-main/artemis/_version.py +30 -0
- package/artemis-main/artemis/agents/__init__.py +17 -0
- package/artemis-main/artemis/agents/checker/checker.json +9 -0
- package/artemis-main/artemis/agents/checker/checker.py +859 -0
- package/artemis-main/artemis/agents/diagnoser/diagnoser.json +23 -0
- package/artemis-main/artemis/agents/diagnoser/diagnoser.py +608 -0
- package/artemis-main/artemis/agents/explorer/constants.py +52 -0
- package/artemis-main/artemis/agents/explorer/explorer.json +57 -0
- package/artemis-main/artemis/agents/explorer/explorer.py +473 -0
- package/artemis-main/artemis/agents/explorer/geometry.py +73 -0
- package/artemis-main/artemis/agents/explorer/native_runner.py +878 -0
- package/artemis-main/artemis/agents/explorer/perception_tools.py +632 -0
- package/artemis-main/artemis/agents/explorer/run_setup.py +403 -0
- package/artemis-main/artemis/agents/explorer/screen_index.py +266 -0
- package/artemis-main/artemis/agents/explorer/tiers.py +110 -0
- package/artemis-main/artemis/agents/explorer/tool_declarations.py +394 -0
- package/artemis-main/artemis/agents/explorer/universal_runner.py +317 -0
- package/artemis-main/artemis/agents/flash/context_compressor.py +452 -0
- package/artemis-main/artemis/agents/flash/flash_runner.md +51 -0
- package/artemis-main/artemis/agents/flash/flash_summarizer.md +53 -0
- package/artemis-main/artemis/agents/flash/flash_summarizer_single.md +54 -0
- package/artemis-main/artemis/agents/flash/runner.py +1167 -0
- package/artemis-main/artemis/agents/flash/summarizer.py +511 -0
- package/artemis-main/artemis/agents/history_analyzer/history_analyzer.md +8 -0
- package/artemis-main/artemis/agents/history_analyzer/history_analyzer.py +182 -0
- package/artemis-main/artemis/agents/image_processor/image_processor.md +74 -0
- package/artemis-main/artemis/agents/image_processor/image_processor.py +322 -0
- package/artemis-main/artemis/agents/log_analyzer/log_analyzer.md +15 -0
- package/artemis-main/artemis/agents/log_analyzer/log_analyzer.py +403 -0
- package/artemis-main/artemis/agents/log_analyzer/log_reader_sub_agent.md +8 -0
- package/artemis-main/artemis/agents/log_analyzer/output_analyzer.md +11 -0
- package/artemis-main/artemis/agents/log_analyzer/output_analyzer.py +163 -0
- package/artemis-main/artemis/agents/object_detector/object_detector.json +9 -0
- package/artemis-main/artemis/agents/object_detector/object_detector.py +211 -0
- package/artemis-main/artemis/agents/operator/operator.json +3 -0
- package/artemis-main/artemis/agents/operator/operator.py +1394 -0
- package/artemis-main/artemis/agents/operator/prompts.py +1064 -0
- package/artemis-main/artemis/agents/outputter/outputter.md +36 -0
- package/artemis-main/artemis/agents/outputter/outputter.py +552 -0
- package/artemis-main/artemis/agents/planner/planner.json +32 -0
- package/artemis-main/artemis/agents/planner/planner.py +436 -0
- package/artemis-main/artemis/agents/prompt_assembly.py +79 -0
- package/artemis-main/artemis/agents/summarizer/summarizer.py +190 -0
- package/artemis-main/artemis/agents/validator/action_execution.py +98 -0
- package/artemis-main/artemis/agents/validator/categories.py +33 -0
- package/artemis-main/artemis/agents/validator/execution_loop.py +488 -0
- package/artemis-main/artemis/agents/validator/incidents.py +120 -0
- package/artemis-main/artemis/agents/validator/pixel_safety_net.md +15 -0
- package/artemis-main/artemis/agents/validator/precondition_pixel.py +320 -0
- package/artemis-main/artemis/agents/validator/precondition_xml.py +672 -0
- package/artemis-main/artemis/agents/validator/tool_declarations.py +332 -0
- package/artemis-main/artemis/agents/validator/validator.py +188 -0
- package/artemis-main/artemis/agents/video_analyzer/__init__.py +15 -0
- package/artemis-main/artemis/agents/video_analyzer/audio_native.py +543 -0
- package/artemis-main/artemis/agents/video_analyzer/blackboard.py +821 -0
- package/artemis-main/artemis/agents/video_analyzer/chunk_agentic.py +455 -0
- package/artemis-main/artemis/agents/video_analyzer/chunk_conversation.py +491 -0
- package/artemis-main/artemis/agents/video_analyzer/chunk_native.py +437 -0
- package/artemis-main/artemis/agents/video_analyzer/conflict_resolution.py +137 -0
- package/artemis-main/artemis/agents/video_analyzer/gemini_files.py +162 -0
- package/artemis-main/artemis/agents/video_analyzer/native_coordinator.py +541 -0
- package/artemis-main/artemis/agents/video_analyzer/reliability.py +128 -0
- package/artemis-main/artemis/agents/video_analyzer/universal_engine.py +487 -0
- package/artemis-main/artemis/agents/video_analyzer/universal_tools.py +323 -0
- package/artemis-main/artemis/agents/video_analyzer/video_analyzer.md +51 -0
- package/artemis-main/artemis/agents/video_analyzer/video_analyzer.py +875 -0
- package/artemis-main/artemis/agents/video_analyzer/video_sub_agent.md +15 -0
- package/artemis-main/artemis/agents/video_analyzer/video_sub_agent_audio.md +12 -0
- package/artemis-main/artemis/clients/accessibility_client.py +438 -0
- package/artemis-main/artemis/clients/screen_client_factory.py +403 -0
- package/artemis-main/artemis/config/__init__.py +309 -0
- package/artemis-main/artemis/config/agent.py +1098 -0
- package/artemis-main/artemis/config/constants.py +151 -0
- package/artemis-main/artemis/config/core/__init__.py +24 -0
- package/artemis-main/artemis/config/core/engine.py +118 -0
- package/artemis-main/artemis/config/core/interpolator.py +78 -0
- package/artemis-main/artemis/config/llm.py +267 -0
- package/artemis-main/artemis/config/paths.py +244 -0
- package/artemis-main/artemis/config/runtime.py +197 -0
- package/artemis-main/artemis/config/settings.py +315 -0
- package/artemis-main/artemis/constants.py +47 -0
- package/artemis-main/artemis/context.py +289 -0
- package/artemis-main/artemis/controllers/__init__.py +41 -0
- package/artemis-main/artemis/controllers/controller_factory.py +41 -0
- package/artemis-main/artemis/controllers/device_controller.py +29 -0
- package/artemis-main/artemis/controllers/types.py +37 -0
- package/artemis-main/artemis/controllers/unified_controller.py +649 -0
- package/artemis-main/artemis/core/__init__.py +21 -0
- package/artemis-main/artemis/core/diagnostics/__init__.py +90 -0
- package/artemis-main/artemis/core/diagnostics/adb_keys.py +270 -0
- package/artemis-main/artemis/core/diagnostics/adb_server_connection.py +330 -0
- package/artemis-main/artemis/core/diagnostics/device_smoke.py +364 -0
- package/artemis-main/artemis/core/diagnostics/emulator_manager.py +501 -0
- package/artemis-main/artemis/core/diagnostics/engine.py +438 -0
- package/artemis-main/artemis/core/diagnostics/hierarchy_parity.py +216 -0
- package/artemis-main/artemis/core/diagnostics/probes/adb_probe.py +887 -0
- package/artemis-main/artemis/core/diagnostics/probes/base.py +45 -0
- package/artemis-main/artemis/core/diagnostics/probes/credentials_probe.py +296 -0
- package/artemis-main/artemis/core/diagnostics/probes/host_probe.py +427 -0
- package/artemis-main/artemis/core/diagnostics/probes/runtime_probe.py +169 -0
- package/artemis-main/artemis/core/diagnostics/probes/toolchain_probe.py +139 -0
- package/artemis-main/artemis/core/diagnostics/readiness.py +83 -0
- package/artemis-main/artemis/core/diagnostics/schema.py +118 -0
- package/artemis-main/artemis/core/tool_declaration.py +43 -0
- package/artemis-main/artemis/core/tool_failure.py +56 -0
- package/artemis-main/artemis/data_engine/context_vars.py +24 -0
- package/artemis-main/artemis/data_engine/engine.py +1615 -0
- package/artemis-main/artemis/data_engine/history_reader.py +142 -0
- package/artemis-main/artemis/data_engine/models.py +131 -0
- package/artemis-main/artemis/data_engine/storage.py +1245 -0
- package/artemis-main/artemis/data_engine/trace.py +727 -0
- package/artemis-main/artemis/drivers/__init__.py +48 -0
- package/artemis-main/artemis/drivers/android/adb_driver.py +507 -0
- package/artemis-main/artemis/drivers/android/hierarchy.py +64 -0
- package/artemis-main/artemis/drivers/android/input_ime.py +120 -0
- package/artemis-main/artemis/drivers/android/recorder.py +57 -0
- package/artemis-main/artemis/drivers/base.py +290 -0
- package/artemis-main/artemis/drivers/cloud/cloud_driver.py +117 -0
- package/artemis-main/artemis/drivers/factory.py +80 -0
- package/artemis-main/artemis/drivers/mock/mock_driver.py +198 -0
- package/artemis-main/artemis/drivers/types.py +67 -0
- package/artemis-main/artemis/graph/checkpoints.py +1243 -0
- package/artemis-main/artemis/graph/graph.py +1055 -0
- package/artemis-main/artemis/graph/perception.py +234 -0
- package/artemis-main/artemis/graph/state.py +151 -0
- package/artemis-main/artemis/graph/visibility.py +238 -0
- package/artemis-main/artemis/interfaces/cli/__init__.py +19 -0
- package/artemis-main/artemis/interfaces/cli/commands/__init__.py +15 -0
- package/artemis-main/artemis/interfaces/cli/commands/batch.py +278 -0
- package/artemis-main/artemis/interfaces/cli/commands/doctor.py +468 -0
- package/artemis-main/artemis/interfaces/cli/commands/helper.py +226 -0
- package/artemis-main/artemis/interfaces/cli/commands/init.py +193 -0
- package/artemis-main/artemis/interfaces/cli/commands/mcp.py +862 -0
- package/artemis-main/artemis/interfaces/cli/commands/run.py +463 -0
- package/artemis-main/artemis/interfaces/cli/commands/server.py +151 -0
- package/artemis-main/artemis/interfaces/cli/commands/server_lifecycle.py +328 -0
- package/artemis-main/artemis/interfaces/cli/commands/trace.py +111 -0
- package/artemis-main/artemis/interfaces/cli/commands/ui.py +404 -0
- package/artemis-main/artemis/interfaces/cli/main.py +109 -0
- package/artemis-main/artemis/interfaces/sdk/__init__.py +31 -0
- package/artemis-main/artemis/interfaces/sdk/client.py +19 -0
- package/artemis-main/artemis/interfaces/sdk/task.py +72 -0
- package/artemis-main/artemis/llm/__init__.py +25 -0
- package/artemis-main/artemis/llm/fake_model.py +179 -0
- package/artemis-main/artemis/llm/google/__init__.py +57 -0
- package/artemis-main/artemis/llm/google/provider.py +185 -0
- package/artemis-main/artemis/llm/google/usage.py +148 -0
- package/artemis-main/artemis/llm/parser.py +32 -0
- package/artemis-main/artemis/llm/reliability.py +267 -0
- package/artemis-main/artemis/llm/router.py +389 -0
- package/artemis-main/artemis/llm/schemas.py +36 -0
- package/artemis-main/artemis/llm/structured.py +196 -0
- package/artemis-main/artemis/main.py +58 -0
- package/artemis-main/artemis/mcp/__init__.py +20 -0
- package/artemis-main/artemis/mcp/action_executor.py +760 -0
- package/artemis-main/artemis/mcp/action_manifest.py +320 -0
- package/artemis-main/artemis/mcp/action_names.py +172 -0
- package/artemis-main/artemis/mcp/action_server.py +202 -0
- package/artemis-main/artemis/mcp/action_session.py +245 -0
- package/artemis-main/artemis/mcp/action_specs.py +868 -0
- package/artemis-main/artemis/mcp/action_types.py +86 -0
- package/artemis-main/artemis/mcp/actuators/__init__.py +21 -0
- package/artemis-main/artemis/mcp/actuators/adb.py +414 -0
- package/artemis-main/artemis/mcp/actuators/base.py +113 -0
- package/artemis-main/artemis/mcp/actuators/mock.py +70 -0
- package/artemis-main/artemis/mcp/adb_server.py +490 -0
- package/artemis-main/artemis/mcp/observation.py +133 -0
- package/artemis-main/artemis/mcp/xml_search_server.py +297 -0
- package/artemis-main/artemis/memory/__init__.py +90 -0
- package/artemis-main/artemis/memory/chunking.py +1843 -0
- package/artemis-main/artemis/memory/context_policy.py +226 -0
- package/artemis-main/artemis/memory/step_capsule.md +73 -0
- package/artemis-main/artemis/memory/step_memory.py +281 -0
- package/artemis-main/artemis/memory/transcript.py +798 -0
- package/artemis-main/artemis/platform/__init__.py +61 -0
- package/artemis-main/artemis/platform/base.py +104 -0
- package/artemis-main/artemis/platform/darwin.py +184 -0
- package/artemis-main/artemis/platform/linux.py +207 -0
- package/artemis-main/artemis/platform/windows.py +193 -0
- package/artemis-main/artemis/resources/__init__.py +46 -0
- package/artemis-main/artemis/runtime/__init__.py +108 -0
- package/artemis-main/artemis/runtime/adb_endpoint.py +173 -0
- package/artemis-main/artemis/runtime/awake_lease.py +283 -0
- package/artemis-main/artemis/runtime/awake_service.py +343 -0
- package/artemis-main/artemis/runtime/cancel_requests.py +254 -0
- package/artemis-main/artemis/runtime/daemon_client.py +422 -0
- package/artemis-main/artemis/runtime/device_lock.py +1013 -0
- package/artemis-main/artemis/runtime/device_pool.py +478 -0
- package/artemis-main/artemis/runtime/helper_manager.py +1030 -0
- package/artemis-main/artemis/runtime/process_probe.py +98 -0
- package/artemis-main/artemis/runtime/server_lifecycle.py +435 -0
- package/artemis-main/artemis/runtime/supervisor.py +121 -0
- package/artemis-main/artemis/runtime/trace_store.py +375 -0
- package/artemis-main/artemis/sdk/__init__.py +26 -0
- package/artemis-main/artemis/sdk/agent.py +485 -0
- package/artemis-main/artemis/sdk/builders/__init__.py +29 -0
- package/artemis-main/artemis/sdk/builders/agent_config_builder.py +474 -0
- package/artemis-main/artemis/sdk/constants.py +15 -0
- package/artemis-main/artemis/sdk/run_outcome.py +58 -0
- package/artemis-main/artemis/sdk/types/__init__.py +61 -0
- package/artemis-main/artemis/sdk/types/agent.py +89 -0
- package/artemis-main/artemis/sdk/utils.py +28 -0
- package/artemis-main/artemis/services/llm.py +1040 -0
- package/artemis-main/artemis/services/token_meter.py +267 -0
- package/artemis-main/artemis/telemetry/__init__.py +35 -0
- package/artemis-main/artemis/telemetry/models.py +64 -0
- package/artemis-main/artemis/telemetry/replay.py +34 -0
- package/artemis-main/artemis/telemetry/storage/json_storage.py +47 -0
- package/artemis-main/artemis/telemetry/tracer.py +85 -0
- package/artemis-main/artemis/toolchain/__init__.py +52 -0
- package/artemis-main/artemis/toolchain/descriptors.py +92 -0
- package/artemis-main/artemis/toolchain/resolver.py +185 -0
- package/artemis-main/artemis/tools/base.py +232 -0
- package/artemis-main/artemis/tools/command_tool.py +1240 -0
- package/artemis-main/artemis/tools/committee_prompts.json +5 -0
- package/artemis-main/artemis/tools/committee_tool.py +422 -0
- package/artemis-main/artemis/tools/diagnoser_submit_answer_tool.py +87 -0
- package/artemis-main/artemis/tools/diagnostic_tool.py +120 -0
- package/artemis-main/artemis/tools/explorer_tool.py +581 -0
- package/artemis-main/artemis/tools/history/__init__.py +398 -0
- package/artemis-main/artemis/tools/history/replay.py +120 -0
- package/artemis-main/artemis/tools/history/screenshot.py +139 -0
- package/artemis-main/artemis/tools/history/search.py +563 -0
- package/artemis-main/artemis/tools/image_processor_tool.py +124 -0
- package/artemis-main/artemis/tools/index.py +47 -0
- package/artemis-main/artemis/tools/log_tool.py +108 -0
- package/artemis-main/artemis/tools/mobile/launch_app.py +132 -0
- package/artemis-main/artemis/tools/mobile/log_utils.py +138 -0
- package/artemis-main/artemis/tools/mobile/ocr.py +202 -0
- package/artemis-main/artemis/tools/mobile/read_hierarchy.py +108 -0
- package/artemis-main/artemis/tools/mobile/read_logs.py +116 -0
- package/artemis-main/artemis/tools/mobile/search_logs.py +260 -0
- package/artemis-main/artemis/tools/object_detection_tool.py +244 -0
- package/artemis-main/artemis/tools/scratchpad.py +819 -0
- package/artemis-main/artemis/tools/system/adb_shell.py +31 -0
- package/artemis-main/artemis/tools/tool_wrapper.py +270 -0
- package/artemis-main/artemis/tools/video_tool.py +261 -0
- package/artemis-main/artemis/tools/wait_tool.py +97 -0
- package/artemis-main/artemis/utils/app_launch_utils.py +207 -0
- package/artemis-main/artemis/utils/coordinates.py +606 -0
- package/artemis-main/artemis/utils/credentials_validator.py +201 -0
- package/artemis-main/artemis/utils/cv_canvas.py +189 -0
- package/artemis-main/artemis/utils/cython_compat.py +45 -0
- package/artemis-main/artemis/utils/element_hit_test.py +80 -0
- package/artemis-main/artemis/utils/image_diff.py +335 -0
- package/artemis-main/artemis/utils/image_hash.py +80 -0
- package/artemis-main/artemis/utils/notes.py +470 -0
- package/artemis-main/artemis/utils/ocr_api.py +105 -0
- package/artemis-main/artemis/utils/ocr_xml_fusion.py +318 -0
- package/artemis-main/artemis/utils/plan_grammar.py +513 -0
- package/artemis-main/artemis/utils/python_executor.py +213 -0
- package/artemis-main/artemis/utils/startup_progress.py +60 -0
- package/artemis-main/artemis/utils/task_tree.py +1174 -0
- package/artemis-main/artemis/utils/text.py +37 -0
- package/artemis-main/artemis/utils/ui_filter.py +651 -0
- package/artemis-main/artemis/utils/video.py +685 -0
- package/artemis-main/artemis/utils/visualization.py +802 -0
- package/artemis-main/config/artemis.example.jsonc +12 -0
- package/artemis-main/mcp_server/README.md +111 -0
- package/artemis-main/mcp_server/__init__.py +21 -0
- package/artemis-main/mcp_server/__main__.py +20 -0
- package/artemis-main/mcp_server/background/__init__.py +15 -0
- package/artemis-main/mcp_server/background/task_runner.py +453 -0
- package/artemis-main/mcp_server/base.py +49 -0
- package/artemis-main/mcp_server/notifiers/__init__.py +74 -0
- package/artemis-main/mcp_server/notifiers/agentapi.py +289 -0
- package/artemis-main/mcp_server/notifiers/base.py +45 -0
- package/artemis-main/mcp_server/notifiers/composite.py +87 -0
- package/artemis-main/mcp_server/notifiers/desktop.py +108 -0
- package/artemis-main/mcp_server/notifiers/file.py +69 -0
- package/artemis-main/mcp_server/notifiers/script.py +90 -0
- package/artemis-main/mcp_server/notifiers/webhook.py +87 -0
- package/artemis-main/mcp_server/rules.md +68 -0
- package/artemis-main/mcp_server/server.py +106 -0
- package/artemis-main/mcp_server/tools/__init__.py +29 -0
- package/artemis-main/mcp_server/tools/device_state.py +107 -0
- package/artemis-main/mcp_server/tools/diagnose.py +1249 -0
- package/artemis-main/mcp_server/tools/inspect_trace.py +394 -0
- package/artemis-main/mcp_server/tools/task_manager.py +627 -0
- package/artemis-main/mcp_server/tools/task_runner.py +548 -0
- package/artemis-main/mcp_server/utils/__init__.py +15 -0
- package/artemis-main/mcp_server/utils/device_utils.py +180 -0
- package/artemis-main/mcp_server/utils/env_utils.py +65 -0
- package/artemis-main/packages/artemis-accessibility-helper/ArtemisAccessibilityHelper.apk +0 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/build.gradle.kts +35 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/AndroidManifest.xml +49 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/A11yNode.java +274 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/ArtemisAccessibilityService.java +227 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/CommandServer.java +463 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/DisplayUtils.java +111 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/GestureController.java +232 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/HierarchyDumper.java +832 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/TokenReceiver.java +36 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/TokenStore.java +38 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/java/com/artemis/helper/XmlUtils.java +102 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/res/values/strings.xml +4 -0
- package/artemis-main/packages/artemis-accessibility-helper/app/src/main/res/xml/accessibility_service_config.xml +10 -0
- package/artemis-main/packages/artemis-accessibility-helper/build.gradle.kts +3 -0
- package/artemis-main/packages/artemis-accessibility-helper/build_apk.sh +215 -0
- package/artemis-main/packages/artemis-accessibility-helper/debug.keystore +0 -0
- package/artemis-main/packages/artemis-accessibility-helper/gradle.properties +2 -0
- package/artemis-main/packages/artemis-accessibility-helper/helper_manifest.json +7 -0
- package/artemis-main/packages/artemis-accessibility-helper/settings.gradle.kts +17 -0
- package/artemis-main/packages/artemis-client/DESIGN.md +89 -0
- package/artemis-main/packages/artemis-client/README.md +112 -0
- package/artemis-main/packages/artemis-client/examples/basic.py +30 -0
- package/artemis-main/packages/artemis-client/pyproject.toml +36 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/__init__.py +45 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/client.py +401 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/errors.py +66 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/models.py +212 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/py.typed +1 -0
- package/artemis-main/packages/artemis-client/src/artemis_client/transport.py +134 -0
- package/artemis-main/packages/artemis-client/tests/test_client.py +289 -0
- package/artemis-main/packages/artemis-client/tests/test_transport.py +85 -0
- package/artemis-main/pyproject.toml +259 -0
- package/artemis-main/pyright-core.json +17 -0
- package/artemis-main/scripts/check_dependency_sources.py +68 -0
- package/artemis-main/scripts/install_deps.ps1 +520 -0
- package/artemis-main/scripts/install_deps.sh +533 -0
- package/artemis-main/scripts/quality_ratchet.py +97 -0
- package/artemis-main/scripts/real_device_video_acceptance.py +483 -0
- package/artemis-main/scripts/run_edge_case_part.py +327 -0
- package/artemis-main/scripts/run_ui.py +242 -0
- package/artemis-main/scripts/start.ps1 +500 -0
- package/artemis-main/scripts/test_all_edge_cases.py +269 -0
- package/artemis-main/scripts/verify_concurrency_and_devices.py +385 -0
- package/artemis-main/setup.py +164 -0
- package/artemis-main/start.bat +35 -0
- package/artemis-main/start.sh +423 -0
- package/artemis-main/third_party/mobile_use/LICENSE +190 -0
- package/artemis-main/third_party/mobile_use/METADATA +27 -0
- package/artemis-main/third_party/mobile_use/NOTICE +12 -0
- package/artemis-main/third_party/mobile_use/__init__.py +19 -0
- package/artemis-main/third_party/mobile_use/agents/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/agents/hopper/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/agents/hopper/hopper.md +22 -0
- package/artemis-main/third_party/mobile_use/agents/hopper/hopper.py +80 -0
- package/artemis-main/third_party/mobile_use/clients/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/clients/ui_automator_client.py +482 -0
- package/artemis-main/third_party/mobile_use/config/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/config/llm.py +183 -0
- package/artemis-main/third_party/mobile_use/config/output.py +184 -0
- package/artemis-main/third_party/mobile_use/context.py +119 -0
- package/artemis-main/third_party/mobile_use/controllers/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/controllers/platform_specific_commands_controller.py +151 -0
- package/artemis-main/third_party/mobile_use/controllers/types.py +92 -0
- package/artemis-main/third_party/mobile_use/controllers/unified_controller.py +183 -0
- package/artemis-main/third_party/mobile_use/graph.py +54 -0
- package/artemis-main/third_party/mobile_use/llm_service.py +193 -0
- package/artemis-main/third_party/mobile_use/main.py +130 -0
- package/artemis-main/third_party/mobile_use/sdk/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/sdk/agent.py +1060 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/agent_config_builder.py +225 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/index.py +33 -0
- package/artemis-main/third_party/mobile_use/sdk/builders/task_request_builder.py +243 -0
- package/artemis-main/third_party/mobile_use/sdk/types/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/sdk/types/agent.py +98 -0
- package/artemis-main/third_party/mobile_use/sdk/types/exceptions.py +109 -0
- package/artemis-main/third_party/mobile_use/sdk/types/task.py +234 -0
- package/artemis-main/third_party/mobile_use/testing.py +59 -0
- package/artemis-main/third_party/mobile_use/tools/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/tools/index.py +44 -0
- package/artemis-main/third_party/mobile_use/tools/mobile/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/tools/mobile/launch_app.py +89 -0
- package/artemis-main/third_party/mobile_use/tools/tool_wrapper.py +52 -0
- package/artemis-main/third_party/mobile_use/utils/__init__.py +13 -0
- package/artemis-main/third_party/mobile_use/utils/app_launch_utils.py +217 -0
- package/artemis-main/third_party/mobile_use/utils/cli_helpers.py +60 -0
- package/artemis-main/third_party/mobile_use/utils/decorators.py +158 -0
- package/artemis-main/third_party/mobile_use/utils/file.py +31 -0
- package/artemis-main/third_party/mobile_use/utils/logger.py +216 -0
- package/artemis-main/third_party/mobile_use/utils/media.py +213 -0
- package/artemis-main/third_party/mobile_use/utils/shell_utils.py +39 -0
- package/artemis-main/third_party/mobile_use/utils/video.py +398 -0
- package/artemis-main/uv.lock +4908 -0
- package/bin/android-midscene-automation.js +1 -5
- package/bin/artemis-config.mjs +15 -0
- package/bin/artemis-embedded.py +56 -0
- package/bin/start-artemis.mjs +30 -0
- package/bin/start-dev.mjs +112 -0
- package/bin/test_artemis_embedded.py +44 -0
- package/package.json +4 -2
- package/server/artemis.ts +34 -0
- package/server/http-api.ts +12 -0
- package/src/App.vue +10 -5
- package/src/api.ts +5 -0
- package/src/appium-recorder/AppiumPage.vue +1 -1
- package/src/appium-recorder/components/ComponentInspector.vue +1 -1
- package/src/appium-recorder/components/FlowNodeSearch.vue +3 -3
- package/src/appium-recorder/components/ImageCheckDialog.vue +3 -3
- package/src/appium-recorder/components/RecorderWorkspace.vue +4 -4
- package/src/appium-recorder/flow-appearance.ts +4 -4
- package/src/components/AppSidebar.vue +8 -7
- package/src/components/MidsceneMaintenanceNotice.vue +17 -0
- package/src/components/analytics/AnalysisCharts.vue +4 -4
- package/src/components/analytics/ReportAnalysis.vue +1 -1
- package/src/components/generator/TestCaseFileUpload.vue +1 -1
- package/src/components/help/HelpCenter.vue +56 -37
- package/src/pages/AiGeneratorPage.vue +1 -1
- package/src/pages/ArtemisPage.vue +72 -0
- package/src/pages/ConfigPage.vue +18 -19
- package/src/style.css +340 -121
- package/src/types.ts +1 -1
|
@@ -0,0 +1,485 @@
|
|
|
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 asyncio
|
|
16
|
+
import inspect
|
|
17
|
+
import os
|
|
18
|
+
import re
|
|
19
|
+
|
|
20
|
+
import uuid
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from dotenv import load_dotenv
|
|
24
|
+
from google import genai
|
|
25
|
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
|
26
|
+
|
|
27
|
+
from artemis.clients.screen_client_factory import (
|
|
28
|
+
describe_backend,
|
|
29
|
+
helper_version,
|
|
30
|
+
hierarchy_backend_sentence,
|
|
31
|
+
)
|
|
32
|
+
from artemis.config import (
|
|
33
|
+
CheckerConfig,
|
|
34
|
+
run_tuning_for_profile,
|
|
35
|
+
settings,
|
|
36
|
+
)
|
|
37
|
+
from artemis.context import (
|
|
38
|
+
ArtemisContext,
|
|
39
|
+
DevicePlatform,
|
|
40
|
+
ExecutionSetup,
|
|
41
|
+
)
|
|
42
|
+
from artemis.data_engine.engine import DataEngine
|
|
43
|
+
from artemis.graph.state import State
|
|
44
|
+
from artemis.runtime import trace_store
|
|
45
|
+
from artemis.runtime.cancel_requests import watch_for_cancel_request
|
|
46
|
+
from artemis.sdk.run_outcome import attach_test_summary, resolve_trace_suffix
|
|
47
|
+
from artemis.sdk.types.agent import AgentConfig
|
|
48
|
+
from artemis.utils.startup_progress import publish_startup_progress
|
|
49
|
+
from third_party.mobile_use.sdk.types.exceptions import AgentError
|
|
50
|
+
from third_party.mobile_use.sdk.types.task import Task
|
|
51
|
+
from third_party.mobile_use.sdk.agent import AgentBase, TOutput
|
|
52
|
+
from third_party.mobile_use.utils.logger import get_logger
|
|
53
|
+
|
|
54
|
+
logger = get_logger(__name__)
|
|
55
|
+
|
|
56
|
+
load_dotenv()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
__all__ = ["Agent", "TOutput", "attach_test_summary", "resolve_trace_suffix", "run_tuning_summary"]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def run_tuning_summary(config: AgentConfig, profile: str | None) -> dict[str, str] | None:
|
|
63
|
+
"""Per-run Pro tuning (verification level, explorer mode) for an SDK config.
|
|
64
|
+
|
|
65
|
+
The SDK config carries the Checker switches as flat flags; fold them back
|
|
66
|
+
into a :class:`CheckerConfig` so the ladder classification stays single-
|
|
67
|
+
sourced in ``artemis.config``. Returns ``None`` for Flash runs.
|
|
68
|
+
"""
|
|
69
|
+
return run_tuning_for_profile(
|
|
70
|
+
profile,
|
|
71
|
+
checker=CheckerConfig(
|
|
72
|
+
enabled=not config.disable_checker,
|
|
73
|
+
midway_checks=not config.disable_midway_checks,
|
|
74
|
+
final_check=not config.disable_final_check,
|
|
75
|
+
assert_failure_policy=config.assert_failure_policy,
|
|
76
|
+
),
|
|
77
|
+
explorer=config.explorer,
|
|
78
|
+
explorer_versions=dict(config.explorer_versions or {}),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class Agent(AgentBase):
|
|
83
|
+
"""Artemis SDK agent."""
|
|
84
|
+
|
|
85
|
+
def __init__(
|
|
86
|
+
self,
|
|
87
|
+
*,
|
|
88
|
+
config: AgentConfig | None = None,
|
|
89
|
+
device_id: str | None = None,
|
|
90
|
+
device_serial: str | None = None,
|
|
91
|
+
concurrency_mode: str | None = None,
|
|
92
|
+
max_concurrency: int | None = None,
|
|
93
|
+
session_id: str | None = None,
|
|
94
|
+
):
|
|
95
|
+
raw_sid = (
|
|
96
|
+
session_id or os.getenv("ARTEMIS_SESSION_ID") or os.getenv("ARTEMIS_CLOUD_SESSION_ID")
|
|
97
|
+
)
|
|
98
|
+
self._session_id: str | None = str(raw_sid).strip() if raw_sid else None
|
|
99
|
+
target_dev = device_serial or device_id
|
|
100
|
+
if config is None:
|
|
101
|
+
from artemis.sdk.builders import Builders
|
|
102
|
+
|
|
103
|
+
builder = Builders.AgentConfig
|
|
104
|
+
if target_dev:
|
|
105
|
+
builder.for_device(DevicePlatform.ANDROID, target_dev)
|
|
106
|
+
if concurrency_mode:
|
|
107
|
+
builder.with_concurrency_mode(concurrency_mode)
|
|
108
|
+
if max_concurrency is not None:
|
|
109
|
+
builder.with_max_concurrency(max_concurrency)
|
|
110
|
+
self._config = builder.build()
|
|
111
|
+
else:
|
|
112
|
+
self._config = config
|
|
113
|
+
updates = {}
|
|
114
|
+
if target_dev:
|
|
115
|
+
updates["device_id"] = target_dev
|
|
116
|
+
updates["device_platform"] = DevicePlatform.ANDROID
|
|
117
|
+
if concurrency_mode:
|
|
118
|
+
updates["concurrency_mode"] = str(concurrency_mode).strip().lower()
|
|
119
|
+
if max_concurrency is not None:
|
|
120
|
+
updates["max_concurrency"] = max_concurrency
|
|
121
|
+
if updates:
|
|
122
|
+
self._config = self._config.model_copy(update=updates)
|
|
123
|
+
|
|
124
|
+
self._tasks = []
|
|
125
|
+
self._tmp_traces_dir = Path(settings.TRACES_PATH)
|
|
126
|
+
self._initialized = False
|
|
127
|
+
self._task_lock = asyncio.Lock()
|
|
128
|
+
|
|
129
|
+
async def _prewarm_llm_connections(self, api_key: str | None = None):
|
|
130
|
+
"""Pre-warms the HTTP2/gRPC connection pools for both Native GenAI and LangChain clients in the background."""
|
|
131
|
+
if os.environ.get("ARTEMIS_FAKE_LLM") == "1":
|
|
132
|
+
logger.info("ARTEMIS_FAKE_LLM=1 — skipping real LLM connection pre-warming.")
|
|
133
|
+
publish_startup_progress(
|
|
134
|
+
"model_ready", "Model connection is ready (fake LLM)", session_id=self._session_id
|
|
135
|
+
)
|
|
136
|
+
return
|
|
137
|
+
publish_startup_progress(
|
|
138
|
+
"model_warmup", "Warming the model connection", session_id=self._session_id
|
|
139
|
+
)
|
|
140
|
+
logger.info("Starting background pre-warming of Gemini API connection pools...")
|
|
141
|
+
try:
|
|
142
|
+
key = api_key
|
|
143
|
+
if not key and settings.GOOGLE_API_KEY:
|
|
144
|
+
key = settings.GOOGLE_API_KEY.get_secret_value()
|
|
145
|
+
|
|
146
|
+
if not key:
|
|
147
|
+
logger.warning("Skipping LLM pre-warming: No API key available.")
|
|
148
|
+
publish_startup_progress(
|
|
149
|
+
"model_ready",
|
|
150
|
+
"Model connection will initialize on first use",
|
|
151
|
+
session_id=self._session_id,
|
|
152
|
+
)
|
|
153
|
+
return
|
|
154
|
+
|
|
155
|
+
# 1. Pre-warm Native SDK client
|
|
156
|
+
client = genai.Client(api_key=key)
|
|
157
|
+
|
|
158
|
+
# 2. Pre-warm LangChain client
|
|
159
|
+
chat = ChatGoogleGenerativeAI(model="gemini-3.8-flash", google_api_key=key)
|
|
160
|
+
|
|
161
|
+
# Fire both calls concurrently in the background
|
|
162
|
+
await asyncio.gather(
|
|
163
|
+
client.aio.models.count_tokens(model="gemini-3.8-flash", contents="ping"),
|
|
164
|
+
chat.ainvoke("ping"),
|
|
165
|
+
return_exceptions=True,
|
|
166
|
+
)
|
|
167
|
+
logger.success("Gemini API connection pools successfully pre-warmed.")
|
|
168
|
+
publish_startup_progress(
|
|
169
|
+
"model_ready", "Model connection is ready", session_id=self._session_id
|
|
170
|
+
)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
logger.warning(f"Failed to pre-warm LLM connections: {e}")
|
|
173
|
+
publish_startup_progress(
|
|
174
|
+
"model_ready",
|
|
175
|
+
"Model connection will initialize on first use",
|
|
176
|
+
session_id=self._session_id,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
async def _watch_external_cancel(self, task_name: str) -> None:
|
|
180
|
+
"""Cancel the running task when another process drops a cancel marker.
|
|
181
|
+
|
|
182
|
+
The admin console (and other ingresses) cannot deliver a signal to a
|
|
183
|
+
worker portably, so they write a marker keyed by session id / pid.
|
|
184
|
+
Reacting here routes the request through the same cancellation path
|
|
185
|
+
as Ctrl+C: the recording is stopped and remuxed, the trace folder is
|
|
186
|
+
compiled and renamed, and the device lease is released.
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
def _on_cancel() -> None:
|
|
190
|
+
logger.warning(
|
|
191
|
+
f"[{task_name}] External cancel request received; stopping the task gracefully."
|
|
192
|
+
)
|
|
193
|
+
self.stop_current_task()
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
await watch_for_cancel_request(_on_cancel, session_id=self._session_id)
|
|
197
|
+
except asyncio.CancelledError:
|
|
198
|
+
raise
|
|
199
|
+
except Exception as exc:
|
|
200
|
+
logger.debug(f"[{task_name}] Cancel watcher stopped: {exc}")
|
|
201
|
+
|
|
202
|
+
async def clean(self, force: bool = False):
|
|
203
|
+
if not self._initialized and not force:
|
|
204
|
+
return
|
|
205
|
+
|
|
206
|
+
if self._ui_adb_client is not None:
|
|
207
|
+
await asyncio.to_thread(self._ui_adb_client.disconnect)
|
|
208
|
+
self._initialized = False
|
|
209
|
+
logger.info("✅ Artemis agent stopped.")
|
|
210
|
+
|
|
211
|
+
async def _ensure_device_unlocked(self) -> None:
|
|
212
|
+
"""Reject secure keyguard instead of allowing an agent to guess credentials."""
|
|
213
|
+
if self._adb_client is None:
|
|
214
|
+
raise AgentError("ADB client is not initialized.")
|
|
215
|
+
|
|
216
|
+
device = self._adb_client.device(serial=self._device_context.device_id)
|
|
217
|
+
try:
|
|
218
|
+
trust_state = str(await asyncio.to_thread(device.shell, "dumpsys trust"))
|
|
219
|
+
except Exception as exc:
|
|
220
|
+
logger.warning(f"Could not inspect Android keyguard state: {exc}")
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
# The first deviceLocked value belongs to the current Android user;
|
|
224
|
+
# later entries may describe a separately locked work profile.
|
|
225
|
+
match = re.search(r"\bdeviceLocked=(?:true|1|false|0)\b", trust_state, re.IGNORECASE)
|
|
226
|
+
if match is None:
|
|
227
|
+
return
|
|
228
|
+
value = match.group(0).split("=", 1)[1].lower()
|
|
229
|
+
if value in {"true", "1"}:
|
|
230
|
+
raise AgentError(
|
|
231
|
+
"Android secure keyguard is locked. Unlock the device manually before "
|
|
232
|
+
"running Artemis; automation will not guess a PIN, password, or pattern."
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
async def _prepare_device_environment(self, context: ArtemisContext):
|
|
236
|
+
"""Prepare device environment flags (like forcing Web Accessibility) before the task runs."""
|
|
237
|
+
if not self._config.force_web_accessibility:
|
|
238
|
+
logger.info(
|
|
239
|
+
"Forcing web accessibility is disabled in AgentConfig. Skipping"
|
|
240
|
+
" device environment prep..."
|
|
241
|
+
)
|
|
242
|
+
return
|
|
243
|
+
|
|
244
|
+
if not self._adb_client or not self._device_context:
|
|
245
|
+
logger.warning(
|
|
246
|
+
"ADB client or device context not available. Skipping device environment prep..."
|
|
247
|
+
)
|
|
248
|
+
return
|
|
249
|
+
|
|
250
|
+
device_id = self._device_context.device_id
|
|
251
|
+
try:
|
|
252
|
+
device = self._adb_client.device(serial=device_id)
|
|
253
|
+
logger.info(f"[{device_id}] ⚙️ Configuring Chrome/WebView Web Accessibility flags...")
|
|
254
|
+
|
|
255
|
+
# 1. Write the force accessibility command flag to Chrome command line
|
|
256
|
+
await asyncio.to_thread(
|
|
257
|
+
device.shell,
|
|
258
|
+
"echo 'chrome --force-renderer-accessibility' >"
|
|
259
|
+
" /data/local/tmp/chrome-command-line",
|
|
260
|
+
)
|
|
261
|
+
await asyncio.to_thread(device.shell, "chmod 555 /data/local/tmp/chrome-command-line")
|
|
262
|
+
|
|
263
|
+
# 2. Write the same command line flag to System WebView config file
|
|
264
|
+
await asyncio.to_thread(
|
|
265
|
+
device.shell,
|
|
266
|
+
"echo 'chrome --force-renderer-accessibility' >"
|
|
267
|
+
" /data/local/tmp/webview-command-line",
|
|
268
|
+
)
|
|
269
|
+
await asyncio.to_thread(device.shell, "chmod 555 /data/local/tmp/webview-command-line")
|
|
270
|
+
|
|
271
|
+
# 3. Force stop Chrome so the flag takes effect next time it launches
|
|
272
|
+
await asyncio.to_thread(device.shell, "am force-stop com.android.chrome")
|
|
273
|
+
logger.success(
|
|
274
|
+
f"[{device_id}] ✅ Chrome Web Accessibility command line flags"
|
|
275
|
+
" configured successfully."
|
|
276
|
+
)
|
|
277
|
+
except Exception as e:
|
|
278
|
+
logger.warning(
|
|
279
|
+
"Failed to configure Chrome Web Accessibility flags (needs"
|
|
280
|
+
f" root/userdebug device): {e}"
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
def _prepare_tracing(self, task: Task, context: ArtemisContext):
|
|
284
|
+
"""Prepare tracing and data engine setup."""
|
|
285
|
+
task_name = self._prepare_trace_paths(task)
|
|
286
|
+
|
|
287
|
+
context.execution_setup = ExecutionSetup(
|
|
288
|
+
traces_path=self._tmp_traces_dir,
|
|
289
|
+
trace_name=task_name,
|
|
290
|
+
enable_remote_tracing=task.request.enable_remote_tracing
|
|
291
|
+
if task.request.record_trace
|
|
292
|
+
else False,
|
|
293
|
+
video_recording_tools_enabled=self._config.video_recording_tools_enabled,
|
|
294
|
+
disable_checker=self._config.disable_checker,
|
|
295
|
+
disable_midway_checks=self._config.disable_midway_checks,
|
|
296
|
+
disable_final_check=self._config.disable_final_check,
|
|
297
|
+
checker_max_iterations=self._config.checker_max_iterations,
|
|
298
|
+
final_check_max_attempts=self._config.final_check_max_attempts,
|
|
299
|
+
checkpoint_max_repairs=self._config.checkpoint_max_repairs,
|
|
300
|
+
max_concurrent_checkpoints=self._config.max_concurrent_checkpoints,
|
|
301
|
+
checkpoint_timeout=self._config.checkpoint_timeout,
|
|
302
|
+
settlement_timeout=self._config.settlement_timeout,
|
|
303
|
+
assert_failure_policy=self._config.assert_failure_policy,
|
|
304
|
+
disable_device_probes=self._config.disable_device_probes,
|
|
305
|
+
disable_planner_validation=self._config.disable_planner_validation,
|
|
306
|
+
enable_committee=self._config.enable_committee,
|
|
307
|
+
committee_debate_rounds=self._config.committee_debate_rounds,
|
|
308
|
+
disable_outputter=self._config.disable_outputter,
|
|
309
|
+
outputter=self._config.outputter,
|
|
310
|
+
explorer=self._config.explorer,
|
|
311
|
+
explorer_versions=self._config.explorer_versions,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
context.data_engine = DataEngine(ctx=context)
|
|
315
|
+
device_data = context.device.model_dump() if context.device else {}
|
|
316
|
+
if task.request.profile:
|
|
317
|
+
device_data["profile"] = task.request.profile
|
|
318
|
+
run_tuning = run_tuning_summary(self._config, task.request.profile)
|
|
319
|
+
if run_tuning:
|
|
320
|
+
device_data["run_tuning"] = run_tuning
|
|
321
|
+
|
|
322
|
+
target_sid = (
|
|
323
|
+
self._session_id
|
|
324
|
+
or os.getenv("ARTEMIS_SESSION_ID")
|
|
325
|
+
or os.getenv("ARTEMIS_CLOUD_SESSION_ID")
|
|
326
|
+
or getattr(task, "id", None)
|
|
327
|
+
or getattr(getattr(task, "request", None), "task_name", None)
|
|
328
|
+
)
|
|
329
|
+
sess_uuid = None
|
|
330
|
+
if target_sid:
|
|
331
|
+
try:
|
|
332
|
+
sess_uuid = uuid.UUID(str(target_sid))
|
|
333
|
+
except Exception:
|
|
334
|
+
sess_uuid = str(target_sid)
|
|
335
|
+
|
|
336
|
+
context.data_engine.start_session(
|
|
337
|
+
goal=task.request.goal,
|
|
338
|
+
device_info=device_data,
|
|
339
|
+
session_id=sess_uuid,
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
async def _finalize_tracing_safely(self, task: Task, context: ArtemisContext):
|
|
343
|
+
"""Finalize optional trace artifacts without changing task semantics."""
|
|
344
|
+
try:
|
|
345
|
+
await self._finalize_tracing(task=task, context=context)
|
|
346
|
+
except Exception as exc:
|
|
347
|
+
logger.error(
|
|
348
|
+
f"[{task.get_name()}] Trace artifact finalization failed after task status "
|
|
349
|
+
f"was resolved as '{task.status}': {exc}",
|
|
350
|
+
exc_info=True,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
def _get_graph_state(self, task: Task):
|
|
354
|
+
return State.initial(task.request.goal)
|
|
355
|
+
|
|
356
|
+
async def _connect_screen_client(self, context: ArtemisContext, session_id: str) -> None:
|
|
357
|
+
"""Connect the screen client with visible progress for slow first-time steps."""
|
|
358
|
+
client = self._ui_adb_client
|
|
359
|
+
previous_listener = getattr(self, "_hierarchy_backend_listener", None)
|
|
360
|
+
if previous_listener is not None:
|
|
361
|
+
previous_client, listener = previous_listener
|
|
362
|
+
previous_client.remove_backend_listener(listener)
|
|
363
|
+
self._hierarchy_backend_listener = None
|
|
364
|
+
publish_startup_progress(
|
|
365
|
+
"uiautomator", "Connecting to the UI hierarchy service", session_id=session_id
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
def on_provision(event: str, details: dict) -> None:
|
|
369
|
+
version = details.get("version_name") or details.get("to_version")
|
|
370
|
+
if event == "installing":
|
|
371
|
+
publish_startup_progress(
|
|
372
|
+
"helper_install",
|
|
373
|
+
"Installing the Artemis accessibility helper on this device for the "
|
|
374
|
+
f"first time (v{version}, about 3 seconds)",
|
|
375
|
+
session_id=session_id,
|
|
376
|
+
**details,
|
|
377
|
+
)
|
|
378
|
+
elif event == "upgrading":
|
|
379
|
+
publish_startup_progress(
|
|
380
|
+
"helper_upgrade",
|
|
381
|
+
"Upgrading the Artemis accessibility helper "
|
|
382
|
+
f"(v{details.get('from_version')} -> v{details.get('to_version')})",
|
|
383
|
+
session_id=session_id,
|
|
384
|
+
**details,
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
# Clients without provisioning (UIAutomator2, cloud) take no callback.
|
|
388
|
+
try:
|
|
389
|
+
accepts_events = "on_event" in inspect.signature(client.connect).parameters
|
|
390
|
+
except (TypeError, ValueError):
|
|
391
|
+
accepts_events = False
|
|
392
|
+
if accepts_events:
|
|
393
|
+
await asyncio.to_thread(client.connect, on_event=on_provision)
|
|
394
|
+
else:
|
|
395
|
+
await asyncio.to_thread(client.connect)
|
|
396
|
+
|
|
397
|
+
backend = describe_backend(client) or "uiautomator"
|
|
398
|
+
publish_startup_progress(
|
|
399
|
+
"uiautomator_ready",
|
|
400
|
+
f"UI hierarchy service is ready ({backend})",
|
|
401
|
+
session_id=session_id,
|
|
402
|
+
)
|
|
403
|
+
self._announce_hierarchy_backend(context, session_id, None, backend, None)
|
|
404
|
+
add_listener = getattr(client, "add_backend_listener", None)
|
|
405
|
+
if callable(add_listener):
|
|
406
|
+
|
|
407
|
+
def listener(previous, new, reason):
|
|
408
|
+
self._announce_hierarchy_backend(context, session_id, previous, new, reason)
|
|
409
|
+
|
|
410
|
+
add_listener(listener)
|
|
411
|
+
self._hierarchy_backend_listener = (client, listener)
|
|
412
|
+
|
|
413
|
+
def _announce_hierarchy_backend(
|
|
414
|
+
self,
|
|
415
|
+
context: ArtemisContext,
|
|
416
|
+
session_id: str,
|
|
417
|
+
previous: str | None,
|
|
418
|
+
backend: str,
|
|
419
|
+
reason: str | None,
|
|
420
|
+
) -> None:
|
|
421
|
+
"""One line everywhere a person or an agent looks for it.
|
|
422
|
+
|
|
423
|
+
Startup-progress event (UI timeline), a named log trace, the session's
|
|
424
|
+
device_info, and status.json for ``mobile_manage_task``. Runs from
|
|
425
|
+
worker threads too, so every sink is best effort.
|
|
426
|
+
"""
|
|
427
|
+
label = {"helper": "Artemis accessibility helper", "uiautomator": "UIAutomator2"}
|
|
428
|
+
version = helper_version(self._ui_adb_client)
|
|
429
|
+
if previous is None:
|
|
430
|
+
message = f"UI hierarchy source: {label.get(backend, backend)}"
|
|
431
|
+
if backend == "helper" and version:
|
|
432
|
+
message += f" v{version}"
|
|
433
|
+
stage = "hierarchy_backend"
|
|
434
|
+
else:
|
|
435
|
+
message = (
|
|
436
|
+
f"UI hierarchy source switched from {label.get(previous, previous)} to "
|
|
437
|
+
f"{label.get(backend, backend)}"
|
|
438
|
+
)
|
|
439
|
+
if reason:
|
|
440
|
+
message += f" because {reason}"
|
|
441
|
+
stage = "hierarchy_backend_changed"
|
|
442
|
+
logger.info(message)
|
|
443
|
+
try:
|
|
444
|
+
publish_startup_progress(
|
|
445
|
+
stage,
|
|
446
|
+
message,
|
|
447
|
+
session_id=session_id,
|
|
448
|
+
backend=backend,
|
|
449
|
+
previous_backend=previous,
|
|
450
|
+
reason=reason,
|
|
451
|
+
helper_version=version,
|
|
452
|
+
)
|
|
453
|
+
except (OSError, ValueError, RuntimeError) as exc:
|
|
454
|
+
logger.debug(f"Could not publish hierarchy backend progress: {exc}")
|
|
455
|
+
engine = getattr(context, "data_engine", None)
|
|
456
|
+
if engine is not None and getattr(engine, "current_session_id", None):
|
|
457
|
+
try:
|
|
458
|
+
engine.record_trace(
|
|
459
|
+
type="log",
|
|
460
|
+
name="hierarchy_backend",
|
|
461
|
+
payload={
|
|
462
|
+
"message": message,
|
|
463
|
+
"backend": backend,
|
|
464
|
+
"previous_backend": previous,
|
|
465
|
+
"reason": reason,
|
|
466
|
+
"helper_version": version,
|
|
467
|
+
"level": "WARNING" if previous is not None else "INFO",
|
|
468
|
+
},
|
|
469
|
+
)
|
|
470
|
+
engine.update_session_device_info(
|
|
471
|
+
hierarchy_backend=backend,
|
|
472
|
+
hierarchy_backend_note=hierarchy_backend_sentence(
|
|
473
|
+
self._ui_adb_client, relative_time=engine.get_relative_time
|
|
474
|
+
),
|
|
475
|
+
)
|
|
476
|
+
except (OSError, ValueError, RuntimeError) as exc:
|
|
477
|
+
logger.debug(f"Could not record hierarchy backend in the data engine: {exc}")
|
|
478
|
+
try:
|
|
479
|
+
trace_store.update_trace_fields(
|
|
480
|
+
session_id,
|
|
481
|
+
hierarchy_backend=backend,
|
|
482
|
+
hierarchy_backend_note=hierarchy_backend_sentence(self._ui_adb_client),
|
|
483
|
+
)
|
|
484
|
+
except (OSError, ValueError, RuntimeError) as exc:
|
|
485
|
+
logger.debug(f"Could not record hierarchy backend in status.json: {exc}")
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
"""Builder classes for configuring ARTEMIS components."""
|
|
16
|
+
|
|
17
|
+
from artemis.sdk.builders.agent_config_builder import AgentConfigBuilder
|
|
18
|
+
from third_party.mobile_use.sdk.builders.index import Builders
|
|
19
|
+
from third_party.mobile_use.sdk.builders.task_request_builder import (
|
|
20
|
+
TaskRequestBuilder,
|
|
21
|
+
TaskRequestCommonBuilder,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"AgentConfigBuilder",
|
|
26
|
+
"TaskRequestCommonBuilder",
|
|
27
|
+
"TaskRequestBuilder",
|
|
28
|
+
"Builders",
|
|
29
|
+
]
|