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,151 @@
|
|
|
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
|
+
"""Centralized constants, environment variable names, and type definitions for ARTEMIS."""
|
|
16
|
+
|
|
17
|
+
from typing import Literal
|
|
18
|
+
|
|
19
|
+
# ==============================================================================
|
|
20
|
+
# Environment Variable Keys
|
|
21
|
+
# ==============================================================================
|
|
22
|
+
|
|
23
|
+
# Application & Workspace Paths
|
|
24
|
+
ENV_ARTEMIS_APP_DIR = "ARTEMIS_APP_DIR"
|
|
25
|
+
ENV_ANTIGRAVITY_APP_DIR = "ANTIGRAVITY_APP_DIR"
|
|
26
|
+
ENV_ARTEMIS_USE_USER_DIR = "ARTEMIS_USE_USER_DIR"
|
|
27
|
+
ENV_ARTEMIS_TRACES_DIR = "ARTEMIS_TRACES_DIR"
|
|
28
|
+
ENV_DATA_ENGINE_DB_PATH = "DATA_ENGINE_DB_PATH"
|
|
29
|
+
|
|
30
|
+
# Cloud Brain & Distributed Execution
|
|
31
|
+
ENV_ARTEMIS_CLOUD_MODE = "ARTEMIS_CLOUD_MODE"
|
|
32
|
+
ENV_ARTEMIS_CLOUD_SESSION_ID = "ARTEMIS_CLOUD_SESSION_ID"
|
|
33
|
+
ENV_ARTEMIS_CLOUD_GATEWAY_URL = "ARTEMIS_CLOUD_GATEWAY_URL"
|
|
34
|
+
ENV_ARTEMIS_TENANT_ID = "ARTEMIS_TENANT_ID"
|
|
35
|
+
ENV_ARTEMIS_TENANT_TOKEN = "ARTEMIS_TENANT_TOKEN"
|
|
36
|
+
ENV_ARTEMIS_EDGE_PORT = "ARTEMIS_EDGE_PORT"
|
|
37
|
+
|
|
38
|
+
# Runtime State & IPC
|
|
39
|
+
ENV_ARTEMIS_IPC_PORT = "ARTEMIS_IPC_PORT"
|
|
40
|
+
ENV_ANTIGRAVITY_LS_ADDRESS = "ANTIGRAVITY_LS_ADDRESS"
|
|
41
|
+
ENV_ARTEMIS_MCP_SERVER = "ARTEMIS_MCP_SERVER"
|
|
42
|
+
|
|
43
|
+
# Device & ADB
|
|
44
|
+
ENV_ADB_DEVICE_SERIAL = "ADB_DEVICE_SERIAL"
|
|
45
|
+
ENV_ARTEMIS_DEVICE_ID = "ARTEMIS_DEVICE_ID"
|
|
46
|
+
ENV_ADB_HOST = "ADB_HOST"
|
|
47
|
+
ENV_ADB_PORT = "ADB_PORT"
|
|
48
|
+
ENV_ADB_SERVER_SOCKET = "ADB_SERVER_SOCKET"
|
|
49
|
+
# UI hierarchy backend: "auto" (helper, UIAutomator2 fallback), "helper", "uiautomator"
|
|
50
|
+
ENV_ARTEMIS_HIERARCHY_BACKEND = "ARTEMIS_HIERARCHY_BACKEND"
|
|
51
|
+
# "true" (default) lets a task install / upgrade the Accessibility Helper APK on a
|
|
52
|
+
# device it holds; "false" only attaches to a helper someone installed by hand.
|
|
53
|
+
ENV_ARTEMIS_HELPER_AUTO_INSTALL = "ARTEMIS_HELPER_AUTO_INSTALL"
|
|
54
|
+
|
|
55
|
+
# LLM & Vision OCR API Keys
|
|
56
|
+
ENV_GOOGLE_API_KEY = "GOOGLE_API_KEY"
|
|
57
|
+
ENV_GEMINI_API_KEY = "GEMINI_API_KEY"
|
|
58
|
+
ENV_GCP_API_KEY = "GCP_API_KEY"
|
|
59
|
+
ENV_OCR_API_KEY = "OCR_API_KEY"
|
|
60
|
+
ENV_VISION_API_KEY = "VISION_API_KEY"
|
|
61
|
+
ENV_API_KEY = "API_KEY"
|
|
62
|
+
ENV_OPENAI_API_KEY = "OPENAI_API_KEY"
|
|
63
|
+
ENV_OPENAI_BASE_URL = "OPENAI_BASE_URL"
|
|
64
|
+
ENV_ANTHROPIC_API_KEY = "ANTHROPIC_API_KEY"
|
|
65
|
+
ENV_OPEN_ROUTER_API_KEY = "OPEN_ROUTER_API_KEY"
|
|
66
|
+
ENV_XAI_API_KEY = "XAI_API_KEY"
|
|
67
|
+
|
|
68
|
+
# Explorer & Agent Defaults
|
|
69
|
+
ENV_ARTEMIS_EXPLORER_VERSION = "ARTEMIS_EXPLORER_VERSION"
|
|
70
|
+
ENV_ARTEMIS_DEFAULT_PROFILE = "ARTEMIS_DEFAULT_PROFILE"
|
|
71
|
+
ENV_ARTEMIS_DEFAULT_MODEL = "ARTEMIS_DEFAULT_MODEL"
|
|
72
|
+
ENV_ARTEMIS_USE_FILE_API = "ARTEMIS_USE_FILE_API"
|
|
73
|
+
|
|
74
|
+
# Debugging & Output Paths
|
|
75
|
+
ENV_KEEP_VIDEOS = "KEEP_VIDEOS"
|
|
76
|
+
ENV_ARTEMIS_DEBUG = "ARTEMIS_DEBUG"
|
|
77
|
+
ENV_EVENTS_OUTPUT_PATH = "EVENTS_OUTPUT_PATH"
|
|
78
|
+
ENV_RESULTS_OUTPUT_PATH = "RESULTS_OUTPUT_PATH"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# ==============================================================================
|
|
82
|
+
# Configuration Filenames
|
|
83
|
+
# ==============================================================================
|
|
84
|
+
|
|
85
|
+
ARTEMIS_CONFIG_FILENAME = "artemis.jsonc"
|
|
86
|
+
LLM_CONFIG_FILENAME = "llm-config.json"
|
|
87
|
+
LLM_CONFIG_OVERRIDE_FILENAME = "llm-config.override.jsonc"
|
|
88
|
+
AGENT_CONFIG_FILENAME = "agent_config.json"
|
|
89
|
+
DATA_ENGINE_DB_FILENAME = "data_engine.db"
|
|
90
|
+
IPC_PORT_FILENAME = ".artemis_ipc_port"
|
|
91
|
+
LS_ADDRESS_FILENAME = ".jetski_ls_address"
|
|
92
|
+
SERVER_INFO_FILENAME = ".artemis_server.json"
|
|
93
|
+
PAUSE_FILENAME = ".artemis_paused"
|
|
94
|
+
REPLAY_DIRNAME = "replay"
|
|
95
|
+
TEST_DATA_DIRNAME = "data"
|
|
96
|
+
TEST_OUTPUTS_DIRNAME = "outputs"
|
|
97
|
+
IMAGES_DIRNAME = "images"
|
|
98
|
+
DOTENV_FILENAME = ".env"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# ==============================================================================
|
|
102
|
+
# Default Values & Network Ports
|
|
103
|
+
# ==============================================================================
|
|
104
|
+
|
|
105
|
+
DEFAULT_ADB_HOST = "127.0.0.1"
|
|
106
|
+
DEFAULT_ADB_PORT = 5037
|
|
107
|
+
DEFAULT_GATEWAY_PORT = 8000
|
|
108
|
+
DEFAULT_EDGE_MONITOR_PORT = 8000
|
|
109
|
+
DEFAULT_ACTION_TIMEOUT = 30.0
|
|
110
|
+
DEFAULT_STREAM_PING_INTERVAL = 15.0
|
|
111
|
+
|
|
112
|
+
DEFAULT_PROFILE = "pro"
|
|
113
|
+
DEFAULT_MODEL = "gemini-2.5-flash"
|
|
114
|
+
DEFAULT_EXPLORER_VERSION: Literal["flash", "pro", "ultra"] = "flash"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# ==============================================================================
|
|
118
|
+
# Literals and Type Aliases
|
|
119
|
+
# ==============================================================================
|
|
120
|
+
|
|
121
|
+
LLMProvider = Literal[
|
|
122
|
+
"openai", "google", "openrouter", "xai", "vertexai", "anthropic", "ollama", "vllm", "custom"
|
|
123
|
+
]
|
|
124
|
+
ExplorerVersion = Literal["flash", "pro", "ultra"]
|
|
125
|
+
|
|
126
|
+
LLMUtilsNode = Literal[
|
|
127
|
+
"outputter",
|
|
128
|
+
"hopper",
|
|
129
|
+
"video_analyzer",
|
|
130
|
+
"object_detector",
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
AgentNode = Literal[
|
|
134
|
+
"planner",
|
|
135
|
+
"summarizer",
|
|
136
|
+
"operator",
|
|
137
|
+
"operator_summarizer",
|
|
138
|
+
"log_reader_sub_agent",
|
|
139
|
+
"log_analyzer",
|
|
140
|
+
"diagnoser",
|
|
141
|
+
"checker",
|
|
142
|
+
"planner_avatar",
|
|
143
|
+
"history_analyzer_expert",
|
|
144
|
+
"diagnoser_expert",
|
|
145
|
+
"explorer",
|
|
146
|
+
"history_analyzer",
|
|
147
|
+
"validator_pixel_safety_net",
|
|
148
|
+
"planner_validation",
|
|
149
|
+
"validator",
|
|
150
|
+
"output_analyzer",
|
|
151
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
"""Artemis unified configuration core."""
|
|
16
|
+
|
|
17
|
+
from artemis.config.core.engine import CascadingConfigEngine, config_engine
|
|
18
|
+
from artemis.config.core.interpolator import interpolate_config_value
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"CascadingConfigEngine",
|
|
22
|
+
"config_engine",
|
|
23
|
+
"interpolate_config_value",
|
|
24
|
+
]
|
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
"""Multi-source Cascading Configuration Engine."""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
import re
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from dotenv import load_dotenv
|
|
23
|
+
|
|
24
|
+
from artemis.config.core.interpolator import interpolate_config_value
|
|
25
|
+
from artemis.platform import platform
|
|
26
|
+
from third_party.mobile_use.utils.logger import get_logger
|
|
27
|
+
|
|
28
|
+
logger = get_logger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _strip_json_comments(text: str) -> str:
|
|
32
|
+
"""Strip // and /* */ comments from JSONC text while preserving string literals."""
|
|
33
|
+
pattern = r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"'
|
|
34
|
+
|
|
35
|
+
def replacer(match: re.Match) -> str:
|
|
36
|
+
s = match.group(0)
|
|
37
|
+
if s.startswith("/"):
|
|
38
|
+
return ""
|
|
39
|
+
return s
|
|
40
|
+
|
|
41
|
+
return re.sub(pattern, replacer, text, flags=re.DOTALL | re.MULTILINE)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _deep_merge(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
|
|
45
|
+
"""Recursively deep merge two dictionaries."""
|
|
46
|
+
merged = base.copy()
|
|
47
|
+
for key, value in override.items():
|
|
48
|
+
if key in merged and isinstance(merged[key], dict) and isinstance(value, dict):
|
|
49
|
+
merged[key] = _deep_merge(merged[key], value)
|
|
50
|
+
else:
|
|
51
|
+
merged[key] = value
|
|
52
|
+
return merged
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class CascadingConfigEngine:
|
|
56
|
+
"""Manages 5-tier configuration hierarchy with automatic cascade and interpolation."""
|
|
57
|
+
|
|
58
|
+
def __init__(self, workspace_root: Path | None = None):
|
|
59
|
+
self.workspace_root = workspace_root or Path.cwd()
|
|
60
|
+
self._load_environment_files()
|
|
61
|
+
|
|
62
|
+
def _load_environment_files(self) -> None:
|
|
63
|
+
"""Load .env files from global config dir and workspace root."""
|
|
64
|
+
# 1. Global user .env
|
|
65
|
+
global_env = platform.paths.config_dir / ".env"
|
|
66
|
+
if global_env.exists():
|
|
67
|
+
load_dotenv(dotenv_path=global_env, override=False, encoding="utf-8")
|
|
68
|
+
|
|
69
|
+
# 2. Legacy ~/.artemis/.env fallback
|
|
70
|
+
legacy_env = platform.paths.data_dir / ".env"
|
|
71
|
+
if legacy_env.exists() and legacy_env != global_env:
|
|
72
|
+
load_dotenv(dotenv_path=legacy_env, override=False, encoding="utf-8")
|
|
73
|
+
|
|
74
|
+
# 3. Workspace .env
|
|
75
|
+
ws_env = self.workspace_root / ".env"
|
|
76
|
+
if ws_env.exists():
|
|
77
|
+
load_dotenv(dotenv_path=ws_env, override=True, encoding="utf-8")
|
|
78
|
+
|
|
79
|
+
def load_raw_config(
|
|
80
|
+
self,
|
|
81
|
+
cli_overrides: dict[str, Any] | None = None,
|
|
82
|
+
) -> dict[str, Any]:
|
|
83
|
+
"""Load and merge all config layers into a unified dictionary."""
|
|
84
|
+
config: dict[str, Any] = {}
|
|
85
|
+
|
|
86
|
+
# Tier 1: Global user configuration ($CONFIG_DIR/artemis.jsonc)
|
|
87
|
+
global_config_path = platform.paths.config_dir / "artemis.jsonc"
|
|
88
|
+
if global_config_path.exists():
|
|
89
|
+
try:
|
|
90
|
+
raw_text = global_config_path.read_text(encoding="utf-8")
|
|
91
|
+
cleaned = _strip_json_comments(raw_text)
|
|
92
|
+
config = _deep_merge(config, json.loads(cleaned))
|
|
93
|
+
except Exception as e:
|
|
94
|
+
logger.warning(f"Failed to load global config {global_config_path}: {e}")
|
|
95
|
+
|
|
96
|
+
# Tier 2: Workspace project configuration (config/artemis.jsonc)
|
|
97
|
+
ws_config_path = self.workspace_root / "config" / "artemis.jsonc"
|
|
98
|
+
if not ws_config_path.exists():
|
|
99
|
+
ws_config_path = self.workspace_root / "artemis.jsonc"
|
|
100
|
+
|
|
101
|
+
if ws_config_path.exists():
|
|
102
|
+
try:
|
|
103
|
+
raw_text = ws_config_path.read_text(encoding="utf-8")
|
|
104
|
+
cleaned = _strip_json_comments(raw_text)
|
|
105
|
+
config = _deep_merge(config, json.loads(cleaned))
|
|
106
|
+
except Exception as e:
|
|
107
|
+
logger.warning(f"Failed to load workspace config {ws_config_path}: {e}")
|
|
108
|
+
|
|
109
|
+
# Tier 3: CLI overrides
|
|
110
|
+
if cli_overrides:
|
|
111
|
+
config = _deep_merge(config, cli_overrides)
|
|
112
|
+
|
|
113
|
+
# Apply variable interpolation across merged dictionary
|
|
114
|
+
interpolated = interpolate_config_value(config, workspace_root=self.workspace_root)
|
|
115
|
+
return interpolated
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
config_engine = CascadingConfigEngine()
|
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
"""Dynamic configuration variable interpolation engine (${env:VAR}, ${path:NAME})."""
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
import re
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from artemis.platform import platform
|
|
23
|
+
|
|
24
|
+
_VAR_PATTERN = re.compile(r"\$\{([^}]+)\}")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _resolve_variable(expr: str, workspace_root: Path | None = None) -> str:
|
|
28
|
+
"""Resolve a single ${namespace:key:-default} expression."""
|
|
29
|
+
expr = expr.strip()
|
|
30
|
+
namespace, _, rest = expr.partition(":")
|
|
31
|
+
if not rest:
|
|
32
|
+
# Defaults to environment variable lookup
|
|
33
|
+
return os.getenv(namespace, f"${{{expr}}}")
|
|
34
|
+
|
|
35
|
+
key, _, default = rest.partition(":-")
|
|
36
|
+
|
|
37
|
+
if namespace == "env":
|
|
38
|
+
return os.getenv(key, default)
|
|
39
|
+
elif namespace == "path":
|
|
40
|
+
paths = platform.paths
|
|
41
|
+
if key == "config_dir":
|
|
42
|
+
return str(paths.config_dir)
|
|
43
|
+
elif key == "data_dir":
|
|
44
|
+
return str(paths.data_dir)
|
|
45
|
+
elif key == "cache_dir":
|
|
46
|
+
return str(paths.cache_dir)
|
|
47
|
+
elif key == "logs_dir":
|
|
48
|
+
return str(paths.logs_dir)
|
|
49
|
+
elif key == "temp_dir":
|
|
50
|
+
return str(paths.temp_dir())
|
|
51
|
+
elif key == "workspace_root" or key == "root_dir":
|
|
52
|
+
return str(workspace_root or Path.cwd())
|
|
53
|
+
return default or f"${{{expr}}}"
|
|
54
|
+
elif namespace == "platform":
|
|
55
|
+
if key == "os_type":
|
|
56
|
+
return platform.os_type.value
|
|
57
|
+
elif key == "path_sep":
|
|
58
|
+
return platform.process.path_separator
|
|
59
|
+
return default or f"${{{expr}}}"
|
|
60
|
+
|
|
61
|
+
return os.getenv(expr, default or f"${{{expr}}}")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def interpolate_config_value(val: Any, workspace_root: Path | None = None) -> Any:
|
|
65
|
+
"""Recursively interpolate strings, lists, and dicts containing ${...} variables."""
|
|
66
|
+
if isinstance(val, str):
|
|
67
|
+
if "${" not in val:
|
|
68
|
+
return val
|
|
69
|
+
|
|
70
|
+
def replacer(match: re.Match) -> str:
|
|
71
|
+
return _resolve_variable(match.group(1), workspace_root)
|
|
72
|
+
|
|
73
|
+
return _VAR_PATTERN.sub(replacer, val)
|
|
74
|
+
elif isinstance(val, dict):
|
|
75
|
+
return {k: interpolate_config_value(v, workspace_root) for k, v in val.items()}
|
|
76
|
+
elif isinstance(val, list):
|
|
77
|
+
return [interpolate_config_value(item, workspace_root) for item in val]
|
|
78
|
+
return val
|
|
@@ -0,0 +1,267 @@
|
|
|
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
|
+
"""LLM provider, model hierarchy, fallback chaining, and configuration loaders."""
|
|
16
|
+
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
from artemis.config.constants import (
|
|
22
|
+
LLM_CONFIG_FILENAME,
|
|
23
|
+
AgentNode,
|
|
24
|
+
)
|
|
25
|
+
from artemis.config.paths import ROOT_DIR, get_config_path
|
|
26
|
+
from artemis.utils.cython_compat import CyFunctionDetector
|
|
27
|
+
from third_party.mobile_use.config import llm as base_llm_config
|
|
28
|
+
from third_party.mobile_use.config.llm import (
|
|
29
|
+
LLM,
|
|
30
|
+
AgentNodeWithFallback,
|
|
31
|
+
LLMConfigBase,
|
|
32
|
+
LLMConfigUtils,
|
|
33
|
+
LLMUtilsNodeWithFallback,
|
|
34
|
+
LLMWithFallback,
|
|
35
|
+
validate_vertex_ai_credentials,
|
|
36
|
+
)
|
|
37
|
+
from third_party.mobile_use.utils.file import load_jsonc
|
|
38
|
+
from third_party.mobile_use.utils.logger import get_logger
|
|
39
|
+
|
|
40
|
+
logger = get_logger(__name__)
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"LLM",
|
|
44
|
+
"AgentNodeWithFallback",
|
|
45
|
+
"LLMUtilsNodeWithFallback",
|
|
46
|
+
"CyFunctionDetector",
|
|
47
|
+
"LLMConfig",
|
|
48
|
+
"LLMConfigUtils",
|
|
49
|
+
"LLMWithFallback",
|
|
50
|
+
"deep_merge_llm_config",
|
|
51
|
+
"get_default_llm_config",
|
|
52
|
+
"initialize_llm_config",
|
|
53
|
+
"lightweight_judge_default",
|
|
54
|
+
"load_llm_config_override",
|
|
55
|
+
"parse_llm_config",
|
|
56
|
+
"validate_vertex_ai_credentials",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def lightweight_judge_default() -> "LLMWithFallback":
|
|
61
|
+
"""Factory default for the lightweight judge nodes (pixel safety net and
|
|
62
|
+
planner validation): a flash-lite model at temperature 0."""
|
|
63
|
+
return LLMWithFallback(
|
|
64
|
+
provider="google",
|
|
65
|
+
model="gemini-3.5-flash-lite",
|
|
66
|
+
temperature=0.0,
|
|
67
|
+
fallback=LLM(
|
|
68
|
+
provider="google",
|
|
69
|
+
model="gemini-3.1-flash-lite",
|
|
70
|
+
temperature=0.0,
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class LLMConfig(LLMConfigBase):
|
|
76
|
+
"""Comprehensive LLM configuration mapping every node to primary/fallback models."""
|
|
77
|
+
|
|
78
|
+
summarizer: LLMWithFallback
|
|
79
|
+
operator: LLMWithFallback
|
|
80
|
+
operator_summarizer: LLMWithFallback
|
|
81
|
+
log_reader_sub_agent: LLMWithFallback
|
|
82
|
+
log_analyzer: LLMWithFallback
|
|
83
|
+
diagnoser: LLMWithFallback
|
|
84
|
+
checker: LLMWithFallback
|
|
85
|
+
planner_avatar: LLMWithFallback
|
|
86
|
+
history_analyzer_expert: LLMWithFallback
|
|
87
|
+
diagnoser_expert: LLMWithFallback
|
|
88
|
+
explorer: LLMWithFallback
|
|
89
|
+
history_analyzer: LLMWithFallback | None = None
|
|
90
|
+
validator_pixel_safety_net: LLMWithFallback | None = None
|
|
91
|
+
planner_validation: LLMWithFallback | None = None
|
|
92
|
+
output_analyzer: LLMWithFallback | None = None
|
|
93
|
+
|
|
94
|
+
def validate_providers(self) -> None:
|
|
95
|
+
"""Validate credentials across all configured agent nodes."""
|
|
96
|
+
super().validate_providers()
|
|
97
|
+
self.summarizer.validate_provider("Summarizer")
|
|
98
|
+
self.operator.validate_provider("Operator")
|
|
99
|
+
self.operator_summarizer.validate_provider("OperatorSummarizer")
|
|
100
|
+
self.log_reader_sub_agent.validate_provider("LogReaderSubAgent")
|
|
101
|
+
self.log_analyzer.validate_provider("LogAnalyzer")
|
|
102
|
+
self.diagnoser.validate_provider("Diagnoser")
|
|
103
|
+
self.checker.validate_provider("Checker")
|
|
104
|
+
self.planner_avatar.validate_provider("PlannerAvatar")
|
|
105
|
+
self.history_analyzer_expert.validate_provider("HistoryAnalyzerExpert")
|
|
106
|
+
self.diagnoser_expert.validate_provider("DiagnoserExpert")
|
|
107
|
+
self.explorer.validate_provider("Explorer")
|
|
108
|
+
if self.history_analyzer:
|
|
109
|
+
self.history_analyzer.validate_provider("HistoryAnalyzer")
|
|
110
|
+
if self.validator_pixel_safety_net:
|
|
111
|
+
self.validator_pixel_safety_net.validate_provider("ValidatorPixelSafetyNet")
|
|
112
|
+
if self.planner_validation:
|
|
113
|
+
self.planner_validation.validate_provider("PlannerValidation")
|
|
114
|
+
if self.output_analyzer:
|
|
115
|
+
self.output_analyzer.validate_provider("OutputAnalyzer")
|
|
116
|
+
|
|
117
|
+
def get_agent(self, item: AgentNode) -> LLMWithFallback:
|
|
118
|
+
"""Retrieve model configuration for a specific agent node with sensible defaults."""
|
|
119
|
+
val = getattr(self, item)
|
|
120
|
+
if val is None:
|
|
121
|
+
if item == "history_analyzer":
|
|
122
|
+
return self.operator
|
|
123
|
+
elif item in ("validator_pixel_safety_net", "planner_validation"):
|
|
124
|
+
# A non-Google installation must not require a hidden Gemini key.
|
|
125
|
+
if self.operator.provider != "google":
|
|
126
|
+
return self.operator
|
|
127
|
+
# Both are cheap, high-frequency judges: the pixel safety net
|
|
128
|
+
# runs before actions, the planner validator after every
|
|
129
|
+
# milestone edit. They share one lightweight default.
|
|
130
|
+
return lightweight_judge_default()
|
|
131
|
+
elif item == "output_analyzer":
|
|
132
|
+
return self.log_analyzer
|
|
133
|
+
return val
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _expand_default_into_nodes(config_dict: dict) -> dict:
|
|
137
|
+
"""Expand unified config format with 'default' and 'nodes' into full LLMConfig schema."""
|
|
138
|
+
if "planner" in config_dict and "utils" in config_dict:
|
|
139
|
+
return config_dict
|
|
140
|
+
|
|
141
|
+
default_model_cfg = config_dict.get(
|
|
142
|
+
"default",
|
|
143
|
+
{
|
|
144
|
+
"provider": "google",
|
|
145
|
+
"model": "gemini-3.8-flash",
|
|
146
|
+
"fallback": {
|
|
147
|
+
"provider": "google",
|
|
148
|
+
"model": "gemini-3.7-flash",
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
nodes_override = config_dict.get("nodes", {})
|
|
154
|
+
|
|
155
|
+
all_agent_nodes = [
|
|
156
|
+
"planner",
|
|
157
|
+
"summarizer",
|
|
158
|
+
"operator",
|
|
159
|
+
"operator_summarizer",
|
|
160
|
+
"log_reader_sub_agent",
|
|
161
|
+
"log_analyzer",
|
|
162
|
+
"diagnoser",
|
|
163
|
+
"checker",
|
|
164
|
+
"planner_avatar",
|
|
165
|
+
"history_analyzer_expert",
|
|
166
|
+
"diagnoser_expert",
|
|
167
|
+
"explorer",
|
|
168
|
+
]
|
|
169
|
+
for node in ("history_analyzer", "validator_pixel_safety_net", "planner_validation", "output_analyzer"):
|
|
170
|
+
if node in nodes_override or (
|
|
171
|
+
node in {"validator_pixel_safety_net", "planner_validation"}
|
|
172
|
+
and default_model_cfg.get("provider") != "google"
|
|
173
|
+
):
|
|
174
|
+
all_agent_nodes.append(node)
|
|
175
|
+
|
|
176
|
+
all_utils_nodes = [
|
|
177
|
+
"outputter",
|
|
178
|
+
"hopper",
|
|
179
|
+
"video_analyzer",
|
|
180
|
+
"object_detector",
|
|
181
|
+
]
|
|
182
|
+
|
|
183
|
+
result: dict[str, Any] = {}
|
|
184
|
+
for node in all_agent_nodes:
|
|
185
|
+
node_cfg = dict(default_model_cfg)
|
|
186
|
+
if node in nodes_override:
|
|
187
|
+
for k, v in nodes_override[node].items():
|
|
188
|
+
if isinstance(v, dict) and isinstance(node_cfg.get(k), dict):
|
|
189
|
+
node_cfg[k] = {**node_cfg[k], **v}
|
|
190
|
+
else:
|
|
191
|
+
node_cfg[k] = v
|
|
192
|
+
result[node] = node_cfg
|
|
193
|
+
|
|
194
|
+
utils_dict: dict[str, Any] = {}
|
|
195
|
+
for util in all_utils_nodes:
|
|
196
|
+
util_cfg = dict(default_model_cfg)
|
|
197
|
+
if util in nodes_override:
|
|
198
|
+
for k, v in nodes_override[util].items():
|
|
199
|
+
if isinstance(v, dict) and isinstance(util_cfg.get(k), dict):
|
|
200
|
+
util_cfg[k] = {**util_cfg[k], **v}
|
|
201
|
+
else:
|
|
202
|
+
util_cfg[k] = v
|
|
203
|
+
utils_dict[util] = util_cfg
|
|
204
|
+
result["utils"] = utils_dict
|
|
205
|
+
|
|
206
|
+
return result
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def parse_llm_config() -> LLMConfig:
|
|
210
|
+
"""Parse and instantiate LLMConfig from artemis.jsonc or llm-config.json."""
|
|
211
|
+
config_path = None
|
|
212
|
+
for candidate in ("artemis.jsonc", "artemis.json", LLM_CONFIG_FILENAME):
|
|
213
|
+
try:
|
|
214
|
+
config_path = get_config_path(candidate)
|
|
215
|
+
break
|
|
216
|
+
except FileNotFoundError:
|
|
217
|
+
continue
|
|
218
|
+
|
|
219
|
+
if not config_path:
|
|
220
|
+
config_path = get_config_path(LLM_CONFIG_FILENAME, ROOT_DIR / LLM_CONFIG_FILENAME)
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
with open(config_path, encoding="utf-8") as f:
|
|
224
|
+
config_dict = load_jsonc(f)
|
|
225
|
+
expanded_dict = _expand_default_into_nodes(config_dict)
|
|
226
|
+
return LLMConfig.model_validate(expanded_dict)
|
|
227
|
+
except Exception as e:
|
|
228
|
+
logger.error(f"Failed to load or parse llm config: {config_path}. Error: {e}")
|
|
229
|
+
raise
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def initialize_llm_config() -> LLMConfig:
|
|
233
|
+
"""Parse and validate credentials for LLMConfig."""
|
|
234
|
+
return base_llm_config.initialize_llm_config(parse_llm_config)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def get_default_llm_config() -> LLMConfig:
|
|
238
|
+
"""Returns default LLMConfig parsed from standard configuration file."""
|
|
239
|
+
return parse_llm_config()
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def deep_merge_llm_config(base: LLMConfig, overrides: dict) -> LLMConfig:
|
|
243
|
+
"""Recursively merge dictionary overrides into an existing LLMConfig object."""
|
|
244
|
+
base_dict = base.model_dump()
|
|
245
|
+
|
|
246
|
+
def merge(d1: dict, d2: dict) -> None:
|
|
247
|
+
for k, v in d2.items():
|
|
248
|
+
if k in d1 and isinstance(d1[k], dict) and isinstance(v, dict):
|
|
249
|
+
merge(d1[k], v)
|
|
250
|
+
else:
|
|
251
|
+
d1[k] = v
|
|
252
|
+
|
|
253
|
+
merge(base_dict, overrides)
|
|
254
|
+
return LLMConfig.model_validate(base_dict)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def load_llm_config_override(path: Path | str) -> LLMConfig:
|
|
258
|
+
"""Load custom LLM configuration JSON/JSONC overrides on top of default configuration."""
|
|
259
|
+
resolved_path = Path(path)
|
|
260
|
+
if not resolved_path.exists():
|
|
261
|
+
try:
|
|
262
|
+
resolved_path = get_config_path(str(path))
|
|
263
|
+
except OSError:
|
|
264
|
+
pass
|
|
265
|
+
return base_llm_config.load_llm_config_override(
|
|
266
|
+
resolved_path, get_default_llm_config, deep_merge_llm_config
|
|
267
|
+
)
|