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,108 @@
|
|
|
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 inspect
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from langchain_core.tools import BaseTool
|
|
19
|
+
from pydantic import BaseModel
|
|
20
|
+
|
|
21
|
+
from artemis.core.tool_failure import ToolFailure
|
|
22
|
+
from artemis.context import ArtemisContext
|
|
23
|
+
from artemis.data_engine.trace import trace_langchain_tool
|
|
24
|
+
from artemis.drivers.base import BaseDeviceDriver
|
|
25
|
+
from artemis.graph.state import State
|
|
26
|
+
from artemis.tools.base import ArtemisTool, ToolCategory
|
|
27
|
+
from artemis.tools.tool_wrapper import ToolWrapper
|
|
28
|
+
from artemis.utils.cython_compat import CyFunctionDetector
|
|
29
|
+
from third_party.mobile_use.utils.logger import get_logger
|
|
30
|
+
|
|
31
|
+
logger = get_logger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class GetUiHierarchyArgs(BaseModel):
|
|
35
|
+
"""Arguments schema for getting UI hierarchy."""
|
|
36
|
+
|
|
37
|
+
model_config = {"ignored_types": (CyFunctionDetector,)}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
GET_UI_HIERARCHY_DOCSTRING = (
|
|
41
|
+
"[DIAGNOSTIC] Retrieves the current screen UI hierarchy XML using a persistent"
|
|
42
|
+
" UI Automator client.\n\nUse this instead of running 'uiautomator dump'"
|
|
43
|
+
" command via adb shell, as it is much faster and more stable."
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class GetUiHierarchyTool(ArtemisTool):
|
|
48
|
+
"""Universal tool for retrieving screen UI hierarchy XML."""
|
|
49
|
+
|
|
50
|
+
def __init__(self, category: ToolCategory = "diagnostic"):
|
|
51
|
+
super().__init__(
|
|
52
|
+
name="get_ui_hierarchy",
|
|
53
|
+
description=GET_UI_HIERARCHY_DOCSTRING,
|
|
54
|
+
args_schema=GetUiHierarchyArgs,
|
|
55
|
+
category=category,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
59
|
+
async def execute(
|
|
60
|
+
self,
|
|
61
|
+
driver: BaseDeviceDriver | None = None,
|
|
62
|
+
ctx: ArtemisContext | None = None,
|
|
63
|
+
tool_call_id: str | None = None, # pylint: disable=unused-argument
|
|
64
|
+
state: State | None = None, # pylint: disable=unused-argument
|
|
65
|
+
**kwargs: Any,
|
|
66
|
+
) -> str:
|
|
67
|
+
try:
|
|
68
|
+
logger.info("get_ui_hierarchy tool called.")
|
|
69
|
+
if ctx is not None and getattr(ctx, "ui_adb_client", None) is not None:
|
|
70
|
+
xml_hierarchy = ctx.ui_adb_client.get_hierarchy()
|
|
71
|
+
if inspect.iscoroutine(xml_hierarchy):
|
|
72
|
+
xml_hierarchy = await xml_hierarchy
|
|
73
|
+
return str(xml_hierarchy)
|
|
74
|
+
if driver is not None and hasattr(driver, "get_screen_data"):
|
|
75
|
+
screen_data = await driver.get_screen_data()
|
|
76
|
+
xml_hierarchy = getattr(screen_data, "ui_hierarchy_xml", None)
|
|
77
|
+
if xml_hierarchy:
|
|
78
|
+
return str(xml_hierarchy)
|
|
79
|
+
return ToolFailure("Error retrieving UI hierarchy: No UI hierarchy in screen data.")
|
|
80
|
+
if driver is not None and hasattr(driver, "get_ui_hierarchy"):
|
|
81
|
+
xml_hierarchy = await driver.get_ui_hierarchy()
|
|
82
|
+
if inspect.iscoroutine(xml_hierarchy):
|
|
83
|
+
xml_hierarchy = await xml_hierarchy
|
|
84
|
+
return str(xml_hierarchy)
|
|
85
|
+
return ToolFailure(
|
|
86
|
+
"Error retrieving UI hierarchy: No UI Automator client or driver provided."
|
|
87
|
+
)
|
|
88
|
+
except Exception as e: # pylint: disable=broad-exception-caught
|
|
89
|
+
logger.error(f"Failed to get UI hierarchy: {e}")
|
|
90
|
+
return ToolFailure(f"Error retrieving UI hierarchy: {e}")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# Universal tool instance & aliases
|
|
94
|
+
get_ui_hierarchy = GetUiHierarchyTool()
|
|
95
|
+
GetUiHierarchy = GetUiHierarchyTool
|
|
96
|
+
GetUIHierarchy = GetUiHierarchyTool
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def get_ui_hierarchy_tool(ctx: ArtemisContext) -> BaseTool:
|
|
100
|
+
"""Exports get_ui_hierarchy as a LangChain BaseTool."""
|
|
101
|
+
return trace_langchain_tool(get_ui_hierarchy.to_langchain_tool(ctx), ctx)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
ui_hierarchy_wrapper = ToolWrapper(
|
|
105
|
+
tool_fn_getter=get_ui_hierarchy_tool,
|
|
106
|
+
on_success_fn=lambda output: output,
|
|
107
|
+
on_failure_fn=lambda error: f"Failed to retrieve UI hierarchy: {error}",
|
|
108
|
+
)
|
|
@@ -0,0 +1,116 @@
|
|
|
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
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
from langchain_core.tools.base import BaseTool
|
|
18
|
+
from pydantic import BaseModel, Field
|
|
19
|
+
|
|
20
|
+
from artemis.core.tool_failure import ToolFailure
|
|
21
|
+
from artemis.context import ArtemisContext
|
|
22
|
+
from artemis.data_engine.trace import trace_langchain_tool
|
|
23
|
+
from artemis.drivers.base import BaseDeviceDriver
|
|
24
|
+
from artemis.graph.state import State
|
|
25
|
+
from artemis.tools.base import ArtemisTool, ToolCategory
|
|
26
|
+
from artemis.tools.mobile.log_utils import fetch_and_filter_logs
|
|
27
|
+
from third_party.mobile_use.utils.logger import get_logger
|
|
28
|
+
|
|
29
|
+
logger = get_logger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ReadLogsArgs(BaseModel):
|
|
33
|
+
"""Arguments schema for read_logs tool."""
|
|
34
|
+
|
|
35
|
+
lines: int | None = Field(
|
|
36
|
+
default=200,
|
|
37
|
+
description=(
|
|
38
|
+
"Number of recent log lines to read. Default is 200. Use larger"
|
|
39
|
+
" numbers only if necessary."
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
since_time: str | None = Field(
|
|
43
|
+
default=None,
|
|
44
|
+
description=(
|
|
45
|
+
"Target timestamp in 'MM-DD HH:MM:SS.ms' format OR relative seconds"
|
|
46
|
+
" (e.g., '15.5') to read logs since. If provided, we will try to"
|
|
47
|
+
" fetch logs starting from this time."
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
until_time: str | None = Field(
|
|
51
|
+
default=None,
|
|
52
|
+
description=(
|
|
53
|
+
"Target timestamp in 'MM-DD HH:MM:SS.ms' format OR relative seconds"
|
|
54
|
+
" (e.g., '20.0') to read logs until. If provided, we will filter"
|
|
55
|
+
" logs up to this time."
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
READ_LOGS_DOCSTRING = (
|
|
61
|
+
"[DIAGNOSTIC] Fetches raw Android logs.\n\n"
|
|
62
|
+
"- Use when: You need to scan logs for a time window or see the sequence"
|
|
63
|
+
" of events.\n"
|
|
64
|
+
"- Input: lines (int, optional): Number of lines to read (default 200)."
|
|
65
|
+
" since_time (str, optional): Timestamp or relative seconds to read since."
|
|
66
|
+
" until_time (str, optional): Timestamp or relative seconds to read until.\n"
|
|
67
|
+
"- Output: Raw log text."
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class ReadLogsTool(ArtemisTool):
|
|
72
|
+
"""Universal tool for fetching raw Android logs."""
|
|
73
|
+
|
|
74
|
+
def __init__(self, category: ToolCategory = "diagnostic"):
|
|
75
|
+
super().__init__(
|
|
76
|
+
name="read_logs",
|
|
77
|
+
description=READ_LOGS_DOCSTRING,
|
|
78
|
+
args_schema=ReadLogsArgs,
|
|
79
|
+
category=category,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
83
|
+
async def execute(
|
|
84
|
+
self,
|
|
85
|
+
driver: BaseDeviceDriver | None = None, # pylint: disable=unused-argument
|
|
86
|
+
ctx: ArtemisContext | None = None,
|
|
87
|
+
lines: int | None = 200,
|
|
88
|
+
since_time: str | None = None,
|
|
89
|
+
until_time: str | None = None,
|
|
90
|
+
tool_call_id: str | None = None, # pylint: disable=unused-argument
|
|
91
|
+
state: State | None = None, # pylint: disable=unused-argument
|
|
92
|
+
**kwargs: Any,
|
|
93
|
+
) -> str:
|
|
94
|
+
try:
|
|
95
|
+
num_lines = 200 if lines is None else lines
|
|
96
|
+
logs = fetch_and_filter_logs(
|
|
97
|
+
ctx=ctx,
|
|
98
|
+
lines=num_lines,
|
|
99
|
+
since_time=since_time,
|
|
100
|
+
until_time=until_time,
|
|
101
|
+
)
|
|
102
|
+
return logs
|
|
103
|
+
except Exception as e: # pylint: disable=broad-exception-caught
|
|
104
|
+
logger.error(f"Failed to read logs: {e}")
|
|
105
|
+
return ToolFailure(f"Failed to read logs: {e}")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# Universal tool instance & aliases
|
|
109
|
+
read_logs = ReadLogsTool()
|
|
110
|
+
ReadLogs = ReadLogsTool
|
|
111
|
+
ReadLogsToolAlias = ReadLogsTool
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def get_read_logs_tool(ctx: ArtemisContext) -> BaseTool:
|
|
115
|
+
"""Exports read_logs as a LangChain BaseTool."""
|
|
116
|
+
return trace_langchain_tool(read_logs.to_langchain_tool(ctx), ctx)
|
|
@@ -0,0 +1,260 @@
|
|
|
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 re
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from langchain_core.tools.base import BaseTool
|
|
19
|
+
from pydantic import BaseModel, Field
|
|
20
|
+
|
|
21
|
+
from artemis.core.tool_failure import ToolFailure
|
|
22
|
+
from artemis.context import ArtemisContext
|
|
23
|
+
from artemis.data_engine.trace import trace_langchain_tool
|
|
24
|
+
from artemis.drivers.base import BaseDeviceDriver
|
|
25
|
+
from artemis.graph.state import State
|
|
26
|
+
from artemis.tools.base import ArtemisTool, ToolCategory
|
|
27
|
+
from artemis.tools.mobile.log_utils import fetch_and_filter_logs
|
|
28
|
+
from third_party.mobile_use.utils.logger import get_logger
|
|
29
|
+
|
|
30
|
+
logger = get_logger(__name__)
|
|
31
|
+
|
|
32
|
+
#: How many line ranges a merged block's header lists before it is cut.
|
|
33
|
+
_MAX_HEADER_RANGES = 8
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _compress_line_numbers(indices: list[int]) -> str:
|
|
37
|
+
"""Renders sorted line numbers as ranges: ``6``, ``69-79``, ``699-798``.
|
|
38
|
+
|
|
39
|
+
Consecutive runs collapse into ``start-end``; at most
|
|
40
|
+
``_MAX_HEADER_RANGES`` ranges are listed, the rest replaced by ``...``.
|
|
41
|
+
"""
|
|
42
|
+
runs: list[str] = []
|
|
43
|
+
start = prev = indices[0]
|
|
44
|
+
for idx in indices[1:]:
|
|
45
|
+
if idx == prev + 1:
|
|
46
|
+
prev = idx
|
|
47
|
+
continue
|
|
48
|
+
runs.append(str(start) if start == prev else f"{start}-{prev}")
|
|
49
|
+
start = prev = idx
|
|
50
|
+
runs.append(str(start) if start == prev else f"{start}-{prev}")
|
|
51
|
+
if len(runs) > _MAX_HEADER_RANGES:
|
|
52
|
+
return ", ".join(runs[:_MAX_HEADER_RANGES]) + ", ..."
|
|
53
|
+
return ", ".join(runs)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# pylint: disable=too-many-branches,too-many-locals,too-many-statements
|
|
57
|
+
def search_and_merge_logs(
|
|
58
|
+
logs: str,
|
|
59
|
+
keyword: str,
|
|
60
|
+
context_lines: int = 50,
|
|
61
|
+
is_regex: bool = False,
|
|
62
|
+
) -> str:
|
|
63
|
+
"""Searches for keyword/pattern in logs and merges overlapping context windows."""
|
|
64
|
+
log_lines = logs.splitlines()
|
|
65
|
+
|
|
66
|
+
if is_regex:
|
|
67
|
+
try:
|
|
68
|
+
pattern = re.compile(keyword, re.IGNORECASE)
|
|
69
|
+
except re.error as e:
|
|
70
|
+
return ToolFailure(f"Error: Invalid regex: {e}")
|
|
71
|
+
else:
|
|
72
|
+
keyword_lower = keyword.lower()
|
|
73
|
+
|
|
74
|
+
# 1. Collect all raw match ranges
|
|
75
|
+
ranges = []
|
|
76
|
+
for i, line in enumerate(log_lines):
|
|
77
|
+
matched = False
|
|
78
|
+
if is_regex:
|
|
79
|
+
if pattern.search(line):
|
|
80
|
+
matched = True
|
|
81
|
+
else:
|
|
82
|
+
if keyword_lower in line.lower():
|
|
83
|
+
matched = True
|
|
84
|
+
|
|
85
|
+
if matched:
|
|
86
|
+
start = max(0, i - context_lines)
|
|
87
|
+
end = min(len(log_lines), i + context_lines + 1)
|
|
88
|
+
ranges.append((start, end, i))
|
|
89
|
+
|
|
90
|
+
if not ranges:
|
|
91
|
+
return f"No matches found for '{keyword}'."
|
|
92
|
+
|
|
93
|
+
# 2. Merge overlapping/adjacent ranges
|
|
94
|
+
ranges.sort(key=lambda x: x[0])
|
|
95
|
+
|
|
96
|
+
merged_ranges = []
|
|
97
|
+
curr_start, curr_end, curr_matches = (
|
|
98
|
+
ranges[0][0],
|
|
99
|
+
ranges[0][1],
|
|
100
|
+
[ranges[0][2]],
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
for start, end, match_idx in ranges[1:]:
|
|
104
|
+
if start <= curr_end: # Overlaps or adjacent
|
|
105
|
+
curr_end = max(curr_end, end)
|
|
106
|
+
curr_matches.append(match_idx)
|
|
107
|
+
else:
|
|
108
|
+
merged_ranges.append((curr_start, curr_end, curr_matches))
|
|
109
|
+
curr_start = start
|
|
110
|
+
curr_end = end
|
|
111
|
+
curr_matches = [match_idx]
|
|
112
|
+
merged_ranges.append((curr_start, curr_end, curr_matches))
|
|
113
|
+
|
|
114
|
+
# 3. Format output
|
|
115
|
+
matches = []
|
|
116
|
+
total_lines = 0
|
|
117
|
+
max_return_lines = 300
|
|
118
|
+
|
|
119
|
+
truncated = False
|
|
120
|
+
for start, end, match_indices in merged_ranges:
|
|
121
|
+
if total_lines >= max_return_lines:
|
|
122
|
+
truncated = True
|
|
123
|
+
break
|
|
124
|
+
|
|
125
|
+
match_str = _compress_line_numbers(match_indices)
|
|
126
|
+
matches.append(f"--- Match at line(s) {match_str} ---")
|
|
127
|
+
for idx in range(start, end):
|
|
128
|
+
line_content = log_lines[idx]
|
|
129
|
+
if idx in match_indices:
|
|
130
|
+
matches.append(f"{idx:4d}: [MATCH] {line_content}")
|
|
131
|
+
else:
|
|
132
|
+
matches.append(f"{idx:4d}: {line_content}")
|
|
133
|
+
|
|
134
|
+
total_lines += 1
|
|
135
|
+
if total_lines >= max_return_lines:
|
|
136
|
+
truncated = True
|
|
137
|
+
break
|
|
138
|
+
|
|
139
|
+
matches.append("-" * 20)
|
|
140
|
+
|
|
141
|
+
if truncated:
|
|
142
|
+
matches.append(
|
|
143
|
+
"\n... [SYSTEM WARNING: Output truncated to protect Context Window."
|
|
144
|
+
" Too many matches exceeded the 300 lines limit. You MUST use a"
|
|
145
|
+
" more specific keyword, narrow the time range, or use"
|
|
146
|
+
" context_lines=0.] ..."
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return "\n".join(matches)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class SearchLogsArgs(BaseModel):
|
|
153
|
+
"""Arguments schema for search_logs tool."""
|
|
154
|
+
|
|
155
|
+
keyword: str = Field(
|
|
156
|
+
...,
|
|
157
|
+
description=("The keyword or regular expression to search for. Case-insensitive."),
|
|
158
|
+
)
|
|
159
|
+
is_regex: bool = Field(
|
|
160
|
+
default=False,
|
|
161
|
+
description=("Whether to treat keyword as a regular expression. Default is False."),
|
|
162
|
+
)
|
|
163
|
+
lines: int | None = Field(
|
|
164
|
+
default=10000,
|
|
165
|
+
description=("Number of recent log lines to search in. Default is 10000."),
|
|
166
|
+
)
|
|
167
|
+
since_time: str | None = Field(
|
|
168
|
+
default=None,
|
|
169
|
+
description=(
|
|
170
|
+
"Target timestamp in 'MM-DD HH:MM:SS.ms' format OR relative seconds"
|
|
171
|
+
" (e.g., '15.5') to search logs since. If provided, we will search"
|
|
172
|
+
" logs starting from this time."
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
until_time: str | None = Field(
|
|
176
|
+
default=None,
|
|
177
|
+
description=(
|
|
178
|
+
"Target timestamp in 'MM-DD HH:MM:SS.ms' format OR relative seconds"
|
|
179
|
+
" (e.g., '20.0') to search logs until. If provided, we will filter"
|
|
180
|
+
" logs up to this time."
|
|
181
|
+
),
|
|
182
|
+
)
|
|
183
|
+
context_lines: int | None = Field(
|
|
184
|
+
default=0,
|
|
185
|
+
description=(
|
|
186
|
+
"Number of lines to include before and after each match for"
|
|
187
|
+
" context. Default is 0. Only increase if you need more context"
|
|
188
|
+
" around a very specific match."
|
|
189
|
+
),
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
SEARCH_LOGS_DOCSTRING = (
|
|
194
|
+
"[DIAGNOSTIC] Searches logs for a keyword or regex pattern.\n\n"
|
|
195
|
+
"- Use when: Looking for specific errors, tags, or keywords without"
|
|
196
|
+
" reading all logs.\n"
|
|
197
|
+
"- Input: keyword (str): Search pattern. is_regex (bool, optional):"
|
|
198
|
+
" Treat keyword as regex. context_lines (int, optional): Lines around"
|
|
199
|
+
" match. since_time (str, optional): Timestamp or relative seconds to"
|
|
200
|
+
" search since. until_time (str, optional): Timestamp or relative seconds"
|
|
201
|
+
" to search until.\n"
|
|
202
|
+
"- Output: Matching lines with context."
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class SearchLogsTool(ArtemisTool):
|
|
207
|
+
"""Universal tool for searching logs for keywords or regex patterns."""
|
|
208
|
+
|
|
209
|
+
def __init__(self, category: ToolCategory = "diagnostic"):
|
|
210
|
+
super().__init__(
|
|
211
|
+
name="search_logs",
|
|
212
|
+
description=SEARCH_LOGS_DOCSTRING,
|
|
213
|
+
args_schema=SearchLogsArgs,
|
|
214
|
+
category=category,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments,too-many-locals
|
|
218
|
+
async def execute(
|
|
219
|
+
self,
|
|
220
|
+
driver: BaseDeviceDriver | None = None, # pylint: disable=unused-argument
|
|
221
|
+
ctx: ArtemisContext | None = None,
|
|
222
|
+
keyword: str = "",
|
|
223
|
+
is_regex: bool = False,
|
|
224
|
+
lines: int | None = 10000,
|
|
225
|
+
since_time: str | None = None,
|
|
226
|
+
until_time: str | None = None,
|
|
227
|
+
context_lines: int | None = 0,
|
|
228
|
+
tool_call_id: str | None = None, # pylint: disable=unused-argument
|
|
229
|
+
state: State | None = None, # pylint: disable=unused-argument
|
|
230
|
+
**kwargs: Any,
|
|
231
|
+
) -> str:
|
|
232
|
+
try:
|
|
233
|
+
num_lines = 10000 if lines is None else lines
|
|
234
|
+
ctx_lines = 0 if context_lines is None else context_lines
|
|
235
|
+
logs = fetch_and_filter_logs(
|
|
236
|
+
ctx=ctx,
|
|
237
|
+
lines=num_lines,
|
|
238
|
+
since_time=since_time,
|
|
239
|
+
until_time=until_time,
|
|
240
|
+
)
|
|
241
|
+
return search_and_merge_logs(
|
|
242
|
+
logs=logs,
|
|
243
|
+
keyword=keyword,
|
|
244
|
+
context_lines=ctx_lines,
|
|
245
|
+
is_regex=is_regex,
|
|
246
|
+
)
|
|
247
|
+
except Exception as e: # pylint: disable=broad-exception-caught
|
|
248
|
+
logger.error(f"Failed to search logs: {e}")
|
|
249
|
+
return ToolFailure(f"Error searching logs: {e}")
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
# Universal tool instance & aliases
|
|
253
|
+
search_logs = SearchLogsTool()
|
|
254
|
+
SearchLogs = SearchLogsTool
|
|
255
|
+
SearchLogsToolAlias = SearchLogsTool
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def get_search_logs_tool(ctx: ArtemisContext) -> BaseTool:
|
|
259
|
+
"""Exports search_logs as a LangChain BaseTool."""
|
|
260
|
+
return trace_langchain_tool(search_logs.to_langchain_tool(ctx), ctx)
|