mobster-cli 0.4.3__py3-none-any.whl
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.
- mobile_agent/__init__.py +4 -0
- mobile_agent/__main__.py +598 -0
- mobile_agent/accounts/__init__.py +1 -0
- mobile_agent/accounts/context.py +80 -0
- mobile_agent/accounts/mcp.py +55 -0
- mobile_agent/accounts/pacing.py +318 -0
- mobile_agent/accounts/register.py +78 -0
- mobile_agent/accounts/routes.py +212 -0
- mobile_agent/accounts/routing.py +69 -0
- mobile_agent/accounts/screen.py +273 -0
- mobile_agent/accounts/stats.py +54 -0
- mobile_agent/accounts/store.py +394 -0
- mobile_agent/agent_hooks.py +123 -0
- mobile_agent/ai_plans/__init__.py +7 -0
- mobile_agent/ai_plans/agents.py +96 -0
- mobile_agent/ai_plans/claude_code.py +208 -0
- mobile_agent/ai_plans/cli.py +400 -0
- mobile_agent/ai_plans/codex.py +258 -0
- mobile_agent/ai_plans/compat_chat.py +307 -0
- mobile_agent/ai_plans/device_login.py +164 -0
- mobile_agent/ai_plans/draft_client.py +68 -0
- mobile_agent/ai_plans/gemini.py +137 -0
- mobile_agent/ai_plans/instructions.py +65 -0
- mobile_agent/ai_plans/mcp_http.py +160 -0
- mobile_agent/ai_plans/phone_tools.py +892 -0
- mobile_agent/ai_plans/providers.py +235 -0
- mobile_agent/ai_plans/routes.py +160 -0
- mobile_agent/ai_plans/runner.py +400 -0
- mobile_agent/ai_plans/vault.py +114 -0
- mobile_agent/alerts.py +337 -0
- mobile_agent/android/__init__.py +18 -0
- mobile_agent/android/adb.py +268 -0
- mobile_agent/android/conditions.py +128 -0
- mobile_agent/android/doctor.py +54 -0
- mobile_agent/android/driver.py +137 -0
- mobile_agent/android/emulator.py +216 -0
- mobile_agent/android/logs.py +85 -0
- mobile_agent/android/manager.py +225 -0
- mobile_agent/android/records.py +31 -0
- mobile_agent/android/tree.py +96 -0
- mobile_agent/answer_shapes.py +230 -0
- mobile_agent/api_devices.py +333 -0
- mobile_agent/api_errors.py +17 -0
- mobile_agent/api_get.py +249 -0
- mobile_agent/api_http.py +467 -0
- mobile_agent/api_post.py +453 -0
- mobile_agent/api_routes.py +173 -0
- mobile_agent/app_api/__init__.py +4 -0
- mobile_agent/app_api/cli.py +151 -0
- mobile_agent/app_api/endpoints.py +193 -0
- mobile_agent/app_api/mcp.py +54 -0
- mobile_agent/app_api/openapi.py +146 -0
- mobile_agent/app_api/reading.py +172 -0
- mobile_agent/app_api/register.py +10 -0
- mobile_agent/app_api/screen.py +216 -0
- mobile_agent/app_api/service.py +382 -0
- mobile_agent/app_api/sessions.py +404 -0
- mobile_agent/app_api/tokens.py +167 -0
- mobile_agent/app_choice.py +131 -0
- mobile_agent/app_icons.py +183 -0
- mobile_agent/app_killer.py +69 -0
- mobile_agent/artifacts.py +606 -0
- mobile_agent/attach/__init__.py +13 -0
- mobile_agent/attach/cli.py +46 -0
- mobile_agent/attach/flutter.py +28 -0
- mobile_agent/attach/score.py +119 -0
- mobile_agent/attach/web.py +13 -0
- mobile_agent/attachments/__init__.py +1 -0
- mobile_agent/attachments/agent.py +418 -0
- mobile_agent/attachments/extract.py +217 -0
- mobile_agent/attachments/mcp.py +104 -0
- mobile_agent/attachments/register.py +73 -0
- mobile_agent/attachments/routes.py +326 -0
- mobile_agent/attachments/service.py +170 -0
- mobile_agent/attachments/sniff.py +152 -0
- mobile_agent/attachments/store.py +441 -0
- mobile_agent/audit_verify.py +436 -0
- mobile_agent/bench/README.md +410 -0
- mobile_agent/bench/__init__.py +0 -0
- mobile_agent/bench/__main__.py +394 -0
- mobile_agent/bench/ab.py +168 -0
- mobile_agent/bench/actuation.py +368 -0
- mobile_agent/bench/agents/__init__.py +9 -0
- mobile_agent/bench/agents/base.py +105 -0
- mobile_agent/bench/agents/plan_clients.py +245 -0
- mobile_agent/bench/agents/smart.py +533 -0
- mobile_agent/bench/checks.py +358 -0
- mobile_agent/bench/decide_gate.py +214 -0
- mobile_agent/bench/diagnose.py +181 -0
- mobile_agent/bench/evals/__init__.py +14 -0
- mobile_agent/bench/evals/build.py +565 -0
- mobile_agent/bench/evals/checkpoint.py +214 -0
- mobile_agent/bench/evals/irt.py +219 -0
- mobile_agent/bench/evals/l0.py +647 -0
- mobile_agent/bench/evals/l1.py +866 -0
- mobile_agent/bench/evals/models.py +124 -0
- mobile_agent/bench/evals/pairwise.py +189 -0
- mobile_agent/bench/evals/proxy.py +90 -0
- mobile_agent/bench/evals/sets.py +149 -0
- mobile_agent/bench/evals/traces.py +446 -0
- mobile_agent/bench/fixtures.py +176 -0
- mobile_agent/bench/guard_replay.py +129 -0
- mobile_agent/bench/h2-manifest.json +20 -0
- mobile_agent/bench/h3-manifest.json +20 -0
- mobile_agent/bench/heldout-manifest.json +32 -0
- mobile_agent/bench/heldout.py +375 -0
- mobile_agent/bench/iosworld.py +901 -0
- mobile_agent/bench/iosworld_stats.py +510 -0
- mobile_agent/bench/llm_units.py +116 -0
- mobile_agent/bench/manifest.json +93 -0
- mobile_agent/bench/metrics.py +66 -0
- mobile_agent/bench/phone.py +44 -0
- mobile_agent/bench/replay.py +172 -0
- mobile_agent/bench/report.py +207 -0
- mobile_agent/bench/runner.py +456 -0
- mobile_agent/bench/safety.py +310 -0
- mobile_agent/bench/stream_timing.py +213 -0
- mobile_agent/bench/suite.py +444 -0
- mobile_agent/bench/sweep.py +176 -0
- mobile_agent/bench/tape.py +798 -0
- mobile_agent/bench/tape_replay.py +88 -0
- mobile_agent/bench/trace_evals.py +128 -0
- mobile_agent/bench/trace_view.py +81 -0
- mobile_agent/bench/truth/iphone15pro.json +138 -0
- mobile_agent/bench/truth.py +340 -0
- mobile_agent/bench/tuning.py +543 -0
- mobile_agent/bench/tuning_analysis.py +656 -0
- mobile_agent/bench/vague-heldout-manifest.json +12 -0
- mobile_agent/bench/vague_rubric.py +135 -0
- mobile_agent/bench/vague_run.py +243 -0
- mobile_agent/brand.py +454 -0
- mobile_agent/brand_fonts.py +756 -0
- mobile_agent/build_identity.py +21 -0
- mobile_agent/cable_bt.py +623 -0
- mobile_agent/cable_bt_runtime.py +128 -0
- mobile_agent/catalog.py +69 -0
- mobile_agent/chart_svg.py +415 -0
- mobile_agent/chat_here.py +189 -0
- mobile_agent/cli_constants.py +5 -0
- mobile_agent/cli_parser.py +611 -0
- mobile_agent/cli_run.py +115 -0
- mobile_agent/compiled_read/__init__.py +21 -0
- mobile_agent/compiled_read/delta.py +89 -0
- mobile_agent/compiled_read/extractors.py +202 -0
- mobile_agent/compiled_read/routes.py +56 -0
- mobile_agent/completion.py +267 -0
- mobile_agent/compose.py +48 -0
- mobile_agent/config.py +114 -0
- mobile_agent/connectors/__init__.py +1 -0
- mobile_agent/connectors/api_session.py +76 -0
- mobile_agent/connectors/callback_page.py +146 -0
- mobile_agent/connectors/client.py +582 -0
- mobile_agent/connectors/github_app.py +55 -0
- mobile_agent/connectors/graph_api.py +396 -0
- mobile_agent/connectors/imports.py +170 -0
- mobile_agent/connectors/issue.py +66 -0
- mobile_agent/connectors/keystore.py +85 -0
- mobile_agent/connectors/marks.py +222 -0
- mobile_agent/connectors/oauth.py +476 -0
- mobile_agent/connectors/picker.py +228 -0
- mobile_agent/connectors/presets.py +591 -0
- mobile_agent/connectors/register.py +48 -0
- mobile_agent/connectors/routes.py +153 -0
- mobile_agent/connectors/service.py +966 -0
- mobile_agent/connectors/shared.py +136 -0
- mobile_agent/connectors/skill.py +446 -0
- mobile_agent/connectors/slack_api.py +269 -0
- mobile_agent/connectors/steps.py +92 -0
- mobile_agent/connectors/store.py +144 -0
- mobile_agent/connectors/vault.py +72 -0
- mobile_agent/console.py +178 -0
- mobile_agent/content_queue/__init__.py +1 -0
- mobile_agent/content_queue/client.py +263 -0
- mobile_agent/content_queue/importing.py +153 -0
- mobile_agent/content_queue/media_check.py +224 -0
- mobile_agent/content_queue/prompt.py +64 -0
- mobile_agent/content_queue/register.py +91 -0
- mobile_agent/content_queue/routes.py +370 -0
- mobile_agent/content_queue/runner.py +475 -0
- mobile_agent/content_queue/store.py +521 -0
- mobile_agent/contract.py +996 -0
- mobile_agent/contract_asks.py +248 -0
- mobile_agent/contract_prompt.py +45 -0
- mobile_agent/contract_screen.py +981 -0
- mobile_agent/contract_view.py +84 -0
- mobile_agent/corpus/__init__.py +26 -0
- mobile_agent/corpus/cli.py +63 -0
- mobile_agent/corpus/consent.py +55 -0
- mobile_agent/corpus/listener.py +76 -0
- mobile_agent/corpus/register.py +9 -0
- mobile_agent/corpus/skeleton.py +72 -0
- mobile_agent/corpus/store.py +143 -0
- mobile_agent/costs.py +161 -0
- mobile_agent/decider_scope.py +40 -0
- mobile_agent/decision_provider.py +189 -0
- mobile_agent/deeplinks.py +352 -0
- mobile_agent/device_info.py +116 -0
- mobile_agent/device_manager.py +978 -0
- mobile_agent/device_status.py +195 -0
- mobile_agent/device_targets.py +217 -0
- mobile_agent/devices.py +676 -0
- mobile_agent/devkit/__init__.py +64 -0
- mobile_agent/devkit/account_cli.py +90 -0
- mobile_agent/devkit/asc.py +562 -0
- mobile_agent/devkit/asc_cli.py +214 -0
- mobile_agent/devkit/ci.py +737 -0
- mobile_agent/devkit/ci_cli.py +196 -0
- mobile_agent/devkit/ci_hosts.py +194 -0
- mobile_agent/devkit/es256.py +197 -0
- mobile_agent/devkit/expo.py +440 -0
- mobile_agent/devkit/expo_cli.py +405 -0
- mobile_agent/devkit/expo_dev.py +203 -0
- mobile_agent/devkit/expo_routes.py +90 -0
- mobile_agent/devkit/fixtures_cli.py +133 -0
- mobile_agent/devkit/fixtures_routes.py +82 -0
- mobile_agent/devkit/links.py +375 -0
- mobile_agent/devkit/links_cli.py +123 -0
- mobile_agent/devkit/links_routes.py +83 -0
- mobile_agent/devkit/nightly.py +152 -0
- mobile_agent/devkit/shots.py +203 -0
- mobile_agent/devkit/testflight.py +155 -0
- mobile_agent/devkit/testflight_cli.py +127 -0
- mobile_agent/devkit/testflight_routes.py +111 -0
- mobile_agent/devkit/xcode.py +236 -0
- mobile_agent/devkit/xcode_cli.py +101 -0
- mobile_agent/devtools.py +419 -0
- mobile_agent/doctor.py +509 -0
- mobile_agent/doctor_fix.py +467 -0
- mobile_agent/downloads.py +55 -0
- mobile_agent/drivers.py +793 -0
- mobile_agent/dry_run.py +102 -0
- mobile_agent/effect_ledger.py +83 -0
- mobile_agent/engine_health.py +378 -0
- mobile_agent/engine_hooks.py +96 -0
- mobile_agent/engines.py +408 -0
- mobile_agent/env_file.py +63 -0
- mobile_agent/env_secrets.py +149 -0
- mobile_agent/errors.py +15 -0
- mobile_agent/evals/__init__.py +3 -0
- mobile_agent/evals/app_survey.py +149 -0
- mobile_agent/evals/development/__init__.py +1 -0
- mobile_agent/evals/development/score.py +276 -0
- mobile_agent/evals/latency_report.py +312 -0
- mobile_agent/evals/offline_report.py +374 -0
- mobile_agent/evals/oracles.py +298 -0
- mobile_agent/evals/redteam/__init__.py +15 -0
- mobile_agent/evals/redteam/__main__.py +72 -0
- mobile_agent/evals/redteam/cases.py +730 -0
- mobile_agent/evals/redteam/harness.py +604 -0
- mobile_agent/evals/redteam/live.py +139 -0
- mobile_agent/evals/redteam/plain.py +85 -0
- mobile_agent/evals/vision/__init__.py +0 -0
- mobile_agent/evals/vision/images/dog_001.jpg +0 -0
- mobile_agent/evals/vision/images/dog_002.jpg +0 -0
- mobile_agent/evals/vision/images/dog_003.jpg +0 -0
- mobile_agent/evals/vision/images/dog_004.jpg +0 -0
- mobile_agent/evals/vision/images/dog_005.jpg +0 -0
- mobile_agent/evals/vision/images/dog_006.jpg +0 -0
- mobile_agent/evals/vision/images/dog_007.jpg +0 -0
- mobile_agent/evals/vision/images/dog_010.jpg +0 -0
- mobile_agent/evals/vision/images/dog_011.jpg +0 -0
- mobile_agent/evals/vision/images/dog_013.jpg +0 -0
- mobile_agent/evals/vision/images/dog_014.jpg +0 -0
- mobile_agent/evals/vision/images/dog_015.jpg +0 -0
- mobile_agent/evals/vision/images/dog_016.jpg +0 -0
- mobile_agent/evals/vision/images/dog_017.jpg +0 -0
- mobile_agent/evals/vision/images/dog_019.jpg +0 -0
- mobile_agent/evals/vision/images/dog_020.jpg +0 -0
- mobile_agent/evals/vision/images/dog_021.jpg +0 -0
- mobile_agent/evals/vision/images/dog_022.jpg +0 -0
- mobile_agent/evals/vision/images/dog_023.jpg +0 -0
- mobile_agent/evals/vision/images/dog_024.jpg +0 -0
- mobile_agent/evals/vision/images/dog_026.jpg +0 -0
- mobile_agent/evals/vision/images/dog_027.jpg +0 -0
- mobile_agent/evals/vision/images/dog_034.jpg +0 -0
- mobile_agent/evals/vision/images/dog_035.jpg +0 -0
- mobile_agent/evals/vision/images/dog_038.jpg +0 -0
- mobile_agent/evals/vision/images/dog_042.jpg +0 -0
- mobile_agent/evals/vision/images/dog_047.jpg +0 -0
- mobile_agent/evals/vision/images/dog_052.jpg +0 -0
- mobile_agent/evals/vision/images/dog_058.jpg +0 -0
- mobile_agent/evals/vision/images/dog_062.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_000.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_010.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_011.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_015.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_016.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_017.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_019.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_021.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_025.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_026.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_027.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_030.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_032.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_033.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_034.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_035.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_036.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_037.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_039.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_040.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_041.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_042.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_043.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_044.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_046.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_047.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_048.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_049.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_051.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_053.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_054.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_055.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_058.jpg +0 -0
- mobile_agent/evals/vision/images/eyes_059.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_002.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_003.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_004.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_007.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_009.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_010.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_011.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_012.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_013.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_014.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_016.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_017.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_023.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_027.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_029.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_032.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_033.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_036.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_041.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_043.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_047.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_049.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_051.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_053.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_056.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_057.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_058.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_059.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_060.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_061.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_062.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_063.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_064.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_065.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_066.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_067.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_068.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_069.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_070.jpg +0 -0
- mobile_agent/evals/vision/images/receipt_071.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_000.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_001.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_002.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_004.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_005.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_008.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_009.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_010.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_012.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_013.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_015.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_016.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_017.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_018.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_021.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_022.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_023.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_024.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_030.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_031.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_032.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_033.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_034.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_036.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_038.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_039.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_040.jpg +0 -0
- mobile_agent/evals/vision/images/sunglasses_041.jpg +0 -0
- mobile_agent/evals/vision/manifest.json +2355 -0
- mobile_agent/eventbus.py +110 -0
- mobile_agent/explain.py +34 -0
- mobile_agent/failure_line.py +197 -0
- mobile_agent/fanout.py +663 -0
- mobile_agent/feedback/__init__.py +2 -0
- mobile_agent/feedback/bundle.py +204 -0
- mobile_agent/feedback/outbox.py +196 -0
- mobile_agent/feedback/register.py +9 -0
- mobile_agent/feedback/routes.py +177 -0
- mobile_agent/fleet.py +841 -0
- mobile_agent/fleet_health.py +729 -0
- mobile_agent/fleet_phone.py +186 -0
- mobile_agent/frontier/__init__.py +79 -0
- mobile_agent/frontier/act.py +380 -0
- mobile_agent/frontier/actions.py +70 -0
- mobile_agent/frontier/agent.py +256 -0
- mobile_agent/frontier/approvals.py +366 -0
- mobile_agent/frontier/hooks.py +199 -0
- mobile_agent/frontier/interrupts.py +125 -0
- mobile_agent/frontier/observe.py +331 -0
- mobile_agent/frontier/phases.py +381 -0
- mobile_agent/frontier/pipeline.py +61 -0
- mobile_agent/frontier/prompt.py +384 -0
- mobile_agent/frontier/protocol.py +91 -0
- mobile_agent/frontier/safety.py +467 -0
- mobile_agent/frontier/saved.py +375 -0
- mobile_agent/frontier/screen.py +419 -0
- mobile_agent/frontier/skills.py +147 -0
- mobile_agent/frontier/stages/__init__.py +1 -0
- mobile_agent/frontier/stages/after.py +192 -0
- mobile_agent/frontier/stages/approve.py +138 -0
- mobile_agent/frontier/stages/controls.py +115 -0
- mobile_agent/frontier/stages/ends.py +102 -0
- mobile_agent/frontier/stages/gate.py +92 -0
- mobile_agent/frontier/stages/guards.py +132 -0
- mobile_agent/frontier/stages/points.py +155 -0
- mobile_agent/frontier/stages/send.py +177 -0
- mobile_agent/frontier/turn.py +151 -0
- mobile_agent/full_disk_access.py +83 -0
- mobile_agent/gemini.py +69 -0
- mobile_agent/genuine.py +120 -0
- mobile_agent/graph/__init__.py +4 -0
- mobile_agent/graph/catalog.py +789 -0
- mobile_agent/graph/chain.py +306 -0
- mobile_agent/graph/dispatch.py +98 -0
- mobile_agent/graph/draft.py +373 -0
- mobile_agent/graph/edit.py +76 -0
- mobile_agent/graph/estimate.py +189 -0
- mobile_agent/graph/expr.py +562 -0
- mobile_agent/graph/functions.py +271 -0
- mobile_agent/graph/infer.py +144 -0
- mobile_agent/graph/nodes.py +936 -0
- mobile_agent/graph/phone_steps.py +178 -0
- mobile_agent/graph/rerun.py +327 -0
- mobile_agent/graph/run.py +899 -0
- mobile_agent/graph/schema.py +842 -0
- mobile_agent/graph/state.py +161 -0
- mobile_agent/graph/values.py +198 -0
- mobile_agent/harness/__init__.py +2 -0
- mobile_agent/harness/checkpoints.py +468 -0
- mobile_agent/harness/control.py +101 -0
- mobile_agent/harness/prewarm.py +213 -0
- mobile_agent/harness/register.py +43 -0
- mobile_agent/harness/routes.py +114 -0
- mobile_agent/harness/settings.py +66 -0
- mobile_agent/harness/tools/__init__.py +67 -0
- mobile_agent/harness/tools/ask_user.py +102 -0
- mobile_agent/harness/tools/watch.py +120 -0
- mobile_agent/harness_api.py +815 -0
- mobile_agent/hedge.py +203 -0
- mobile_agent/help_topics.py +305 -0
- mobile_agent/hints.py +248 -0
- mobile_agent/history.py +69 -0
- mobile_agent/home.py +214 -0
- mobile_agent/http_pool.py +175 -0
- mobile_agent/image_policy.py +139 -0
- mobile_agent/inbox.py +148 -0
- mobile_agent/installed_apps.py +344 -0
- mobile_agent/integrations/__init__.py +1 -0
- mobile_agent/integrations/cli.py +472 -0
- mobile_agent/integrations/client_files.py +65 -0
- mobile_agent/integrations/clients.py +998 -0
- mobile_agent/integrations/doctor.py +185 -0
- mobile_agent/integrations/jsonc.py +383 -0
- mobile_agent/integrations/routes.py +135 -0
- mobile_agent/integrations/rules.py +112 -0
- mobile_agent/integrations/server_options.py +46 -0
- mobile_agent/integrations/skill.py +152 -0
- mobile_agent/integrations/skill_files.py +10 -0
- mobile_agent/integrations/textedit.py +309 -0
- mobile_agent/intents/__init__.py +17 -0
- mobile_agent/intents/atlas.py +216 -0
- mobile_agent/intents/callback.py +44 -0
- mobile_agent/intents/cli.py +55 -0
- mobile_agent/intents/harvest.py +91 -0
- mobile_agent/intents/plan.py +93 -0
- mobile_agent/ios/__init__.py +1 -0
- mobile_agent/ios/guide.py +16 -0
- mobile_agent/ios/kb.py +212 -0
- mobile_agent/ios/kb_data.py +1588 -0
- mobile_agent/ios/mcp.py +44 -0
- mobile_agent/ios/register.py +8 -0
- mobile_agent/ios/system.py +369 -0
- mobile_agent/journal.py +531 -0
- mobile_agent/keychain_acl.py +374 -0
- mobile_agent/keys.py +395 -0
- mobile_agent/latency_overlap.py +36 -0
- mobile_agent/latency_trace.py +170 -0
- mobile_agent/learned/__init__.py +15 -0
- mobile_agent/learned/app_path.py +160 -0
- mobile_agent/learned/code_read.py +38 -0
- mobile_agent/learned/parts.py +546 -0
- mobile_agent/learned/programs.py +691 -0
- mobile_agent/learned/register.py +171 -0
- mobile_agent/learned/routes.py +61 -0
- mobile_agent/learned/taught.py +329 -0
- mobile_agent/learned/teach.py +538 -0
- mobile_agent/learned/workflows.py +647 -0
- mobile_agent/learned/zero.py +41 -0
- mobile_agent/links.py +37 -0
- mobile_agent/listen.py +607 -0
- mobile_agent/lock_spike.py +278 -0
- mobile_agent/lockscreen.py +526 -0
- mobile_agent/login.py +354 -0
- mobile_agent/longform/__init__.py +15 -0
- mobile_agent/longform/ads.py +191 -0
- mobile_agent/longform/blocks.py +117 -0
- mobile_agent/longform/budget.py +265 -0
- mobile_agent/longform/context.py +285 -0
- mobile_agent/longform/costs.py +93 -0
- mobile_agent/longform/digest.py +145 -0
- mobile_agent/longform/extract.py +508 -0
- mobile_agent/longform/feed.py +505 -0
- mobile_agent/longform/followup.py +168 -0
- mobile_agent/longform/frames.py +82 -0
- mobile_agent/longform/identity.py +87 -0
- mobile_agent/longform/inbox.py +221 -0
- mobile_agent/longform/items.py +425 -0
- mobile_agent/longform/models.py +115 -0
- mobile_agent/longform/notebook.py +329 -0
- mobile_agent/longform/plan.py +614 -0
- mobile_agent/longform/recall.py +195 -0
- mobile_agent/longform/receipts.py +81 -0
- mobile_agent/longform/register.py +124 -0
- mobile_agent/longform/report.py +343 -0
- mobile_agent/longform/routes.py +102 -0
- mobile_agent/longform/session.py +644 -0
- mobile_agent/longform/store.py +146 -0
- mobile_agent/longform/synthesis.py +347 -0
- mobile_agent/mac_tools.py +223 -0
- mobile_agent/manual_control.py +143 -0
- mobile_agent/maps.py +149 -0
- mobile_agent/marks.py +92 -0
- mobile_agent/mcp_server/__init__.py +3 -0
- mobile_agent/mcp_server/__main__.py +29 -0
- mobile_agent/mcp_server/action_journal.py +24 -0
- mobile_agent/mcp_server/action_tools.py +638 -0
- mobile_agent/mcp_server/approvals.py +219 -0
- mobile_agent/mcp_server/catalog.py +92 -0
- mobile_agent/mcp_server/cli.py +194 -0
- mobile_agent/mcp_server/codes.py +147 -0
- mobile_agent/mcp_server/device_tools.py +306 -0
- mobile_agent/mcp_server/direct.py +272 -0
- mobile_agent/mcp_server/expo_tools.py +105 -0
- mobile_agent/mcp_server/phone_tools.py +510 -0
- mobile_agent/mcp_server/protocol.py +364 -0
- mobile_agent/mcp_server/registry.py +55 -0
- mobile_agent/mcp_server/run_tools.py +531 -0
- mobile_agent/mcp_server/schemas.py +425 -0
- mobile_agent/mcp_server/screen_tools.py +168 -0
- mobile_agent/mcp_server/session.py +469 -0
- mobile_agent/mcp_server/support.py +145 -0
- mobile_agent/mcp_server/tools.py +493 -0
- mobile_agent/memory/__init__.py +9 -0
- mobile_agent/memory/cli.py +207 -0
- mobile_agent/memory/extract.py +191 -0
- mobile_agent/memory/listener.py +100 -0
- mobile_agent/memory/model.py +144 -0
- mobile_agent/memory/project.py +96 -0
- mobile_agent/memory/provider.py +127 -0
- mobile_agent/memory/register.py +21 -0
- mobile_agent/memory/retrieval.py +172 -0
- mobile_agent/memory/routes.py +216 -0
- mobile_agent/memory/runs.py +124 -0
- mobile_agent/memory/store.py +806 -0
- mobile_agent/memory/writer.py +278 -0
- mobile_agent/mirroring.py +585 -0
- mobile_agent/mirroring_runtime.py +221 -0
- mobile_agent/model_clients.py +604 -0
- mobile_agent/narrate.py +813 -0
- mobile_agent/native_helpers.py +84 -0
- mobile_agent/netxray/__init__.py +1 -0
- mobile_agent/netxray/analyze.py +322 -0
- mobile_agent/netxray/attribution.py +62 -0
- mobile_agent/netxray/capture.py +88 -0
- mobile_agent/netxray/cli.py +142 -0
- mobile_agent/netxray/job.py +219 -0
- mobile_agent/netxray/mobster-pcap.c +560 -0
- mobile_agent/netxray/packets.py +410 -0
- mobile_agent/netxray/pcapng.py +223 -0
- mobile_agent/netxray/register.py +93 -0
- mobile_agent/netxray/report.py +214 -0
- mobile_agent/netxray/store.py +48 -0
- mobile_agent/netxray/summary.py +157 -0
- mobile_agent/netxray/target.py +67 -0
- mobile_agent/netxray/tool.py +66 -0
- mobile_agent/netxray/trackers.py +194 -0
- mobile_agent/notify_triggers/__init__.py +1 -0
- mobile_agent/notify_triggers/rules.py +39 -0
- mobile_agent/notify_triggers/sources.py +315 -0
- mobile_agent/notify_triggers/watch.py +135 -0
- mobile_agent/offers.py +86 -0
- mobile_agent/orchestrate.py +215 -0
- mobile_agent/outlets/__init__.py +1 -0
- mobile_agent/outlets/connect.py +249 -0
- mobile_agent/outlets/folder.py +180 -0
- mobile_agent/outlets/hooks.py +453 -0
- mobile_agent/outlets/inbound.py +472 -0
- mobile_agent/outlets/inbound_reply.py +57 -0
- mobile_agent/outlets/inbound_routes.py +81 -0
- mobile_agent/outlets/kinds.py +308 -0
- mobile_agent/outlets/mail.py +110 -0
- mobile_agent/outlets/net.py +86 -0
- mobile_agent/outlets/notion.py +244 -0
- mobile_agent/outlets/register.py +56 -0
- mobile_agent/outlets/routes.py +135 -0
- mobile_agent/outlets/service.py +580 -0
- mobile_agent/outlets/sheets.py +169 -0
- mobile_agent/outlets/slack.py +177 -0
- mobile_agent/outlets/store.py +194 -0
- mobile_agent/outlets/vault.py +80 -0
- mobile_agent/outlets/webhook.py +316 -0
- mobile_agent/output_contract.py +141 -0
- mobile_agent/owner_presence.py +211 -0
- mobile_agent/ownership.py +219 -0
- mobile_agent/packs/__init__.py +1 -0
- mobile_agent/packs/calendar.py +243 -0
- mobile_agent/packs/context.py +68 -0
- mobile_agent/packs/core.py +757 -0
- mobile_agent/packs/front_door.py +316 -0
- mobile_agent/packs/heal.py +214 -0
- mobile_agent/packs/health.py +122 -0
- mobile_agent/packs/insights.py +76 -0
- mobile_agent/packs/instagram.py +640 -0
- mobile_agent/packs/linkedin.py +106 -0
- mobile_agent/packs/maps.py +196 -0
- mobile_agent/packs/mcp.py +149 -0
- mobile_agent/packs/messages.py +270 -0
- mobile_agent/packs/notes.py +226 -0
- mobile_agent/packs/photos.py +166 -0
- mobile_agent/packs/pins.py +47 -0
- mobile_agent/packs/reddit.py +110 -0
- mobile_agent/packs/register.py +276 -0
- mobile_agent/packs/rows.py +108 -0
- mobile_agent/packs/safari.py +143 -0
- mobile_agent/packs/settings.py +253 -0
- mobile_agent/packs/social.py +300 -0
- mobile_agent/packs/threads.py +97 -0
- mobile_agent/packs/tiktok.py +455 -0
- mobile_agent/packs/tools.py +290 -0
- mobile_agent/packs/x.py +127 -0
- mobile_agent/packs/youtube.py +199 -0
- mobile_agent/parity.py +270 -0
- mobile_agent/paths.py +99 -0
- mobile_agent/perception.py +470 -0
- mobile_agent/permissions/__init__.py +32 -0
- mobile_agent/permissions/consequence.py +535 -0
- mobile_agent/permissions/exceptions.py +99 -0
- mobile_agent/permissions/gate.py +316 -0
- mobile_agent/permissions/outside.py +316 -0
- mobile_agent/permissions/policy.py +288 -0
- mobile_agent/permissions/project_policy.py +411 -0
- mobile_agent/permissions/register.py +148 -0
- mobile_agent/permissions/rules.py +291 -0
- mobile_agent/phone_io/__init__.py +146 -0
- mobile_agent/phone_io/cli.py +427 -0
- mobile_agent/phone_io/clipboard.py +78 -0
- mobile_agent/phone_io/controls.py +78 -0
- mobile_agent/phone_io/files.py +289 -0
- mobile_agent/phone_io/handoff.py +123 -0
- mobile_agent/phone_io/icloud.py +118 -0
- mobile_agent/phone_io/install.py +188 -0
- mobile_agent/phone_io/network_capture.py +188 -0
- mobile_agent/phone_io/network_cli.py +138 -0
- mobile_agent/phone_io/network_profiles.py +138 -0
- mobile_agent/phone_io/photos.py +512 -0
- mobile_agent/phone_io/recording.py +115 -0
- mobile_agent/phone_io/secrets.py +146 -0
- mobile_agent/phone_io/transfer.py +895 -0
- mobile_agent/phone_io/tunnel.py +129 -0
- mobile_agent/phone_ready.py +91 -0
- mobile_agent/pinning.py +158 -0
- mobile_agent/plan_gate.py +807 -0
- mobile_agent/plugins/__init__.py +3 -0
- mobile_agent/plugins/install.py +163 -0
- mobile_agent/plugins/manifest.py +242 -0
- mobile_agent/plugins/register.py +15 -0
- mobile_agent/plugins/routes.py +82 -0
- mobile_agent/plugins/service.py +322 -0
- mobile_agent/plugins/skills.py +76 -0
- mobile_agent/plugins/store.py +79 -0
- mobile_agent/pool.py +285 -0
- mobile_agent/power_watch.py +275 -0
- mobile_agent/premium_model.py +22 -0
- mobile_agent/project_env.py +291 -0
- mobile_agent/project_env_cli.py +74 -0
- mobile_agent/project_env_routes.py +55 -0
- mobile_agent/projects/__init__.py +27 -0
- mobile_agent/projects/ci.py +332 -0
- mobile_agent/projects/clone.py +339 -0
- mobile_agent/projects/drafts.py +158 -0
- mobile_agent/projects/folder.py +436 -0
- mobile_agent/projects/github.py +131 -0
- mobile_agent/projects/register.py +31 -0
- mobile_agent/projects/revisions.py +253 -0
- mobile_agent/projects/routes.py +234 -0
- mobile_agent/projects/runs.py +297 -0
- mobile_agent/projects/service.py +695 -0
- mobile_agent/projects/setup.py +84 -0
- mobile_agent/projects/store.py +379 -0
- mobile_agent/projects/sync.py +380 -0
- mobile_agent/projects/workflow_files.py +270 -0
- mobile_agent/replay_core/__init__.py +26 -0
- mobile_agent/replay_core/checks.py +594 -0
- mobile_agent/replay_core/engine.py +596 -0
- mobile_agent/replay_core/heal.py +364 -0
- mobile_agent/replay_core/path.py +240 -0
- mobile_agent/replay_core/recorder.py +206 -0
- mobile_agent/replay_core/store.py +171 -0
- mobile_agent/result_blocks.py +941 -0
- mobile_agent/run.py +642 -0
- mobile_agent/run_delivery.py +123 -0
- mobile_agent/run_executor.py +200 -0
- mobile_agent/run_export.py +284 -0
- mobile_agent/run_gif.py +891 -0
- mobile_agent/runner_hints.py +86 -0
- mobile_agent/runner_renewal.py +205 -0
- mobile_agent/runtime_create.py +549 -0
- mobile_agent/runtime_driver.py +458 -0
- mobile_agent/runtime_limits.py +319 -0
- mobile_agent/runtime_queue.py +394 -0
- mobile_agent/runtime_runs.py +383 -0
- mobile_agent/runtime_status.py +181 -0
- mobile_agent/runtime_teach.py +295 -0
- mobile_agent/runtime_work.py +599 -0
- mobile_agent/screen_text.py +101 -0
- mobile_agent/secret_filter.py +113 -0
- mobile_agent/serve.py +160 -0
- mobile_agent/server.py +363 -0
- mobile_agent/service_support.py +42 -0
- mobile_agent/settle/__init__.py +1 -0
- mobile_agent/settle/predict.py +102 -0
- mobile_agent/settle/replay.py +92 -0
- mobile_agent/settle/store.py +93 -0
- mobile_agent/settle/stream.py +43 -0
- mobile_agent/setup_cli.py +225 -0
- mobile_agent/setup_errors.py +87 -0
- mobile_agent/setup_service.py +527 -0
- mobile_agent/share.py +104 -0
- mobile_agent/signing.py +184 -0
- mobile_agent/sim/__init__.py +6 -0
- mobile_agent/sim/__main__.py +26 -0
- mobile_agent/sim/api.py +952 -0
- mobile_agent/sim/apps.py +172 -0
- mobile_agent/sim/biometrics.py +84 -0
- mobile_agent/sim/cli.py +271 -0
- mobile_agent/sim/doctor.py +293 -0
- mobile_agent/sim/governor.py +90 -0
- mobile_agent/sim/holders.py +88 -0
- mobile_agent/sim/models.py +62 -0
- mobile_agent/sim/registry.py +161 -0
- mobile_agent/sim/simctl.py +269 -0
- mobile_agent/sim/wda.py +618 -0
- mobile_agent/sim/xcode.py +74 -0
- mobile_agent/skills/__init__.py +12 -0
- mobile_agent/skills/codes.py +597 -0
- mobile_agent/skills/notifications.py +281 -0
- mobile_agent/skills/open_url.py +127 -0
- mobile_agent/smart_events.py +588 -0
- mobile_agent/smart_result.py +490 -0
- mobile_agent/smart_run.py +413 -0
- mobile_agent/state.py +662 -0
- mobile_agent/states.py +217 -0
- mobile_agent/steering.py +70 -0
- mobile_agent/style.py +178 -0
- mobile_agent/supervised.py +234 -0
- mobile_agent/swift/helper_bt_hid.swift +534 -0
- mobile_agent/swift/helper_doc_text.swift +184 -0
- mobile_agent/swift/helper_draft_reply.swift +170 -0
- mobile_agent/swift/helper_map.swift +110 -0
- mobile_agent/swift/helper_mirroring.swift +1099 -0
- mobile_agent/swift/helper_mjpeg_mp4.swift +103 -0
- mobile_agent/swift/helper_pdf.swift +100 -0
- mobile_agent/swift/helper_phone_audio.swift +993 -0
- mobile_agent/swift/helper_phone_screen.swift +416 -0
- mobile_agent/swift/helper_screen_text.swift +24 -0
- mobile_agent/swift/helper_transfer.swift +246 -0
- mobile_agent/swift/ocr.swift +22 -0
- mobile_agent/task_policy.py +337 -0
- mobile_agent/team_signing/__init__.py +34 -0
- mobile_agent/team_signing/apple_ca.py +37 -0
- mobile_agent/team_signing/bundle.py +136 -0
- mobile_agent/team_signing/cli.py +208 -0
- mobile_agent/team_signing/identity.py +248 -0
- mobile_agent/team_signing/ledger.py +105 -0
- mobile_agent/team_signing/prebuilt.py +61 -0
- mobile_agent/team_signing/resign.py +256 -0
- mobile_agent/team_signing/service.py +382 -0
- mobile_agent/team_signing/tooling.py +243 -0
- mobile_agent/team_signing/writes.py +268 -0
- mobile_agent/terminal_image.py +81 -0
- mobile_agent/testkit/__init__.py +1 -0
- mobile_agent/testkit/a11y_baseline.py +132 -0
- mobile_agent/testkit/api.py +403 -0
- mobile_agent/testkit/capsule.py +400 -0
- mobile_agent/testkit/capsule_cli.py +57 -0
- mobile_agent/testkit/cli.py +948 -0
- mobile_agent/testkit/cli_arguments.py +193 -0
- mobile_agent/testkit/comparison.py +288 -0
- mobile_agent/testkit/comparison_cli.py +41 -0
- mobile_agent/testkit/discover.py +257 -0
- mobile_agent/testkit/editor.py +243 -0
- mobile_agent/testkit/execute.py +515 -0
- mobile_agent/testkit/github_checks.py +248 -0
- mobile_agent/testkit/gitref.py +66 -0
- mobile_agent/testkit/heal_review.py +176 -0
- mobile_agent/testkit/health.py +480 -0
- mobile_agent/testkit/history.py +255 -0
- mobile_agent/testkit/hosted_results.py +321 -0
- mobile_agent/testkit/input_files.py +173 -0
- mobile_agent/testkit/jobs.py +285 -0
- mobile_agent/testkit/junit_verdict.py +33 -0
- mobile_agent/testkit/maestro.py +802 -0
- mobile_agent/testkit/mcp.py +562 -0
- mobile_agent/testkit/mcp_comparison.py +88 -0
- mobile_agent/testkit/minimize.py +471 -0
- mobile_agent/testkit/minimizer_cli.py +48 -0
- mobile_agent/testkit/notify.py +212 -0
- mobile_agent/testkit/phone_video.py +191 -0
- mobile_agent/testkit/pr.py +491 -0
- mobile_agent/testkit/pr_report.py +562 -0
- mobile_agent/testkit/prbuild.py +148 -0
- mobile_agent/testkit/proof_report.py +55 -0
- mobile_agent/testkit/provenance.py +119 -0
- mobile_agent/testkit/prrun.py +244 -0
- mobile_agent/testkit/recent.py +166 -0
- mobile_agent/testkit/recipes.py +146 -0
- mobile_agent/testkit/record.py +204 -0
- mobile_agent/testkit/register.py +288 -0
- mobile_agent/testkit/reports.py +998 -0
- mobile_agent/testkit/repro.py +432 -0
- mobile_agent/testkit/scenario.py +440 -0
- mobile_agent/testkit/scenario_cli.py +37 -0
- mobile_agent/testkit/snapshots_cli.py +60 -0
- mobile_agent/testkit/suite.py +670 -0
- mobile_agent/testkit/targets.py +497 -0
- mobile_agent/testkit/xctest.py +378 -0
- mobile_agent/threads/__init__.py +1 -0
- mobile_agent/threads/chat_once.py +264 -0
- mobile_agent/threads/cli.py +740 -0
- mobile_agent/threads/client.py +326 -0
- mobile_agent/threads/context.py +246 -0
- mobile_agent/threads/mcp.py +739 -0
- mobile_agent/threads/recent.py +34 -0
- mobile_agent/threads/register.py +54 -0
- mobile_agent/threads/routes.py +188 -0
- mobile_agent/threads/service.py +975 -0
- mobile_agent/threads/store.py +361 -0
- mobile_agent/threads/summary.py +117 -0
- mobile_agent/threads/term.py +101 -0
- mobile_agent/threads/workflow_cli.py +104 -0
- mobile_agent/tls.py +36 -0
- mobile_agent/traces.py +271 -0
- mobile_agent/tracks.py +235 -0
- mobile_agent/transport.py +271 -0
- mobile_agent/triggers/__init__.py +1 -0
- mobile_agent/triggers/actions.py +204 -0
- mobile_agent/triggers/model.py +146 -0
- mobile_agent/triggers/register.py +29 -0
- mobile_agent/triggers/routes.py +101 -0
- mobile_agent/triggers/service.py +387 -0
- mobile_agent/triggers/store.py +142 -0
- mobile_agent/tui/__init__.py +89 -0
- mobile_agent/tui/app.py +582 -0
- mobile_agent/tui/chrome.py +321 -0
- mobile_agent/tui/commands.py +375 -0
- mobile_agent/tui/demo_phone.py +369 -0
- mobile_agent/tui/images.py +29 -0
- mobile_agent/tui/keys.py +64 -0
- mobile_agent/tui/prompt.py +195 -0
- mobile_agent/tui/render.py +395 -0
- mobile_agent/tui/screens.py +180 -0
- mobile_agent/tui/session.py +308 -0
- mobile_agent/tui/tasks.py +287 -0
- mobile_agent/tui/theme.py +118 -0
- mobile_agent/tui/widgets.py +272 -0
- mobile_agent/update_check.py +213 -0
- mobile_agent/usage.py +184 -0
- mobile_agent/verify/__init__.py +0 -0
- mobile_agent/verify/__main__.py +41 -0
- mobile_agent/verify/a11y.py +189 -0
- mobile_agent/verify/actions.py +290 -0
- mobile_agent/verify/assertions.py +570 -0
- mobile_agent/verify/audit.py +312 -0
- mobile_agent/verify/business.py +221 -0
- mobile_agent/verify/business_run.py +131 -0
- mobile_agent/verify/business_state.py +168 -0
- mobile_agent/verify/check_schema.py +398 -0
- mobile_agent/verify/checks.py +614 -0
- mobile_agent/verify/cli.py +423 -0
- mobile_agent/verify/conditions.py +483 -0
- mobile_agent/verify/crashes.py +321 -0
- mobile_agent/verify/device_audit.py +246 -0
- mobile_agent/verify/dialogs.py +287 -0
- mobile_agent/verify/evidence.py +705 -0
- mobile_agent/verify/fixtures.py +305 -0
- mobile_agent/verify/flow.py +213 -0
- mobile_agent/verify/l10n.py +141 -0
- mobile_agent/verify/netcerts.py +67 -0
- mobile_agent/verify/netproxy.py +356 -0
- mobile_agent/verify/netrun.py +81 -0
- mobile_agent/verify/netshim.m +28 -0
- mobile_agent/verify/netshim.py +48 -0
- mobile_agent/verify/netstubs.py +132 -0
- mobile_agent/verify/overlay.py +174 -0
- mobile_agent/verify/perf.py +239 -0
- mobile_agent/verify/proof.py +192 -0
- mobile_agent/verify/replay_admission.py +48 -0
- mobile_agent/verify/report.py +952 -0
- mobile_agent/verify/run_cleanup.py +67 -0
- mobile_agent/verify/run_links.py +48 -0
- mobile_agent/verify/run_perf.py +44 -0
- mobile_agent/verify/run_secrets.py +39 -0
- mobile_agent/verify/runner.py +976 -0
- mobile_agent/verify/runs.py +57 -0
- mobile_agent/verify/screen_coverage.py +181 -0
- mobile_agent/verify/smart.py +106 -0
- mobile_agent/verify/snapshot_run.py +114 -0
- mobile_agent/verify/snapshots.py +306 -0
- mobile_agent/verify/sound.py +335 -0
- mobile_agent/verify/source_observation.py +130 -0
- mobile_agent/verify/system_surfaces/__init__.py +7 -0
- mobile_agent/verify/system_surfaces/play.py +106 -0
- mobile_agent/verify/system_surfaces/spec.py +139 -0
- mobile_agent/verify/system_surfaces/stage.py +138 -0
- mobile_agent/verify/system_surfaces/surfaces.py +121 -0
- mobile_agent/verify/tree.py +223 -0
- mobile_agent/verify/verdict.py +377 -0
- mobile_agent/verify/wire.py +392 -0
- mobile_agent/verify/wirestore.py +176 -0
- mobile_agent/waiting/__init__.py +1 -0
- mobile_agent/waiting/contacts.py +73 -0
- mobile_agent/waiting/drafts.py +136 -0
- mobile_agent/waiting/job.py +145 -0
- mobile_agent/waiting/messages.py +174 -0
- mobile_agent/waiting/rank.py +115 -0
- mobile_agent/waiting/register.py +26 -0
- mobile_agent/watch.py +502 -0
- mobile_agent/wda/__init__.py +2 -0
- mobile_agent/wda/frame_clock.py +646 -0
- mobile_agent/wda/frame_source.py +325 -0
- mobile_agent/wda/frame_store.py +115 -0
- mobile_agent/wda/gate.py +163 -0
- mobile_agent/wda/gestures.py +291 -0
- mobile_agent/wda/guards.py +94 -0
- mobile_agent/wda/identity.py +55 -0
- mobile_agent/wda/observe.py +884 -0
- mobile_agent/wda/patches.py +856 -0
- mobile_agent/wda/point_gestures.py +150 -0
- mobile_agent/wda/source.py +32 -0
- mobile_agent/wda/system_dialogs.py +571 -0
- mobile_agent/wda/text.py +694 -0
- mobile_agent/wda/timeouts.py +77 -0
- mobile_agent/wda/video.py +505 -0
- mobile_agent/wda/watchdog.py +243 -0
- mobile_agent/wireless/__init__.py +15 -0
- mobile_agent/wireless/api.py +354 -0
- mobile_agent/wireless/cli.py +287 -0
- mobile_agent/wireless/devicectl.py +229 -0
- mobile_agent/wireless/exposure.py +33 -0
- mobile_agent/wireless/mobster-wifi-pair.c +122 -0
- mobile_agent/wireless/monitor.py +332 -0
- mobile_agent/wireless/network.py +334 -0
- mobile_agent/wireless/onboarding.py +293 -0
- mobile_agent/wireless/pair.py +124 -0
- mobile_agent/wireless/probe.py +322 -0
- mobile_agent/wireless/register.py +8 -0
- mobile_agent/wireless/relay.py +179 -0
- mobile_agent/wireless/result.py +87 -0
- mobile_agent/wireless/store.py +85 -0
- mobile_agent/wireless/switch.py +77 -0
- mobile_agent/wireless/transport.py +118 -0
- mobile_agent/wireless/words.py +81 -0
- mobile_agent/wireless/xctestrun.py +83 -0
- mobile_agent/workflow_tools.py +59 -0
- mobile_agent/workflows/__init__.py +2 -0
- mobile_agent/workflows/brief.py +201 -0
- mobile_agent/workflows/cron.py +110 -0
- mobile_agent/workflows/health.py +257 -0
- mobile_agent/workflows/history.py +126 -0
- mobile_agent/workflows/records.py +442 -0
- mobile_agent/workflows/runs.py +1000 -0
- mobile_agent/workflows/scheduler.py +134 -0
- mobile_agent/workflows/service.py +973 -0
- mobile_agent/workflows/starters.py +285 -0
- mobile_agent/workflows/triggers.py +248 -0
- mobile_agent/xray/__init__.py +1 -0
- mobile_agent/xray/app_cli.py +116 -0
- mobile_agent/xray/cli.py +21 -0
- mobile_agent/xray/crawl.py +754 -0
- mobile_agent/xray/diff.py +171 -0
- mobile_agent/xray/diff_cli.py +43 -0
- mobile_agent/xray/job.py +184 -0
- mobile_agent/xray/paywall.py +188 -0
- mobile_agent/xray/policy.py +305 -0
- mobile_agent/xray/register.py +43 -0
- mobile_agent/xray/report.py +283 -0
- mobile_agent/xray/screens.py +117 -0
- mobster_cli-0.4.3.dist-info/METADATA +93 -0
- mobster_cli-0.4.3.dist-info/RECORD +1009 -0
- mobster_cli-0.4.3.dist-info/WHEEL +5 -0
- mobster_cli-0.4.3.dist-info/entry_points.txt +3 -0
- mobster_cli-0.4.3.dist-info/licenses/LICENSE +21 -0
- mobster_cli-0.4.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""The stages that refuse an action for what came before it: an unknown outcome, a loop, a request that did not ask
|
|
2
|
+
for it."""
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
from ...task_policy import is_keypad_key
|
|
7
|
+
from ..act import DISMISS_POINTS, SUBMIT_WINDOW_SECONDS
|
|
8
|
+
from ..protocol import HOUSEKEEPING_OPS, TYPED_OPS
|
|
9
|
+
from ..safety import LOOP_REPEATS, REPEAT_ACT_AGAIN, REPEAT_ACT_FEEDBACK, guard
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def unknown_outcome(agent, attempt, turn):
|
|
13
|
+
index = turn.index
|
|
14
|
+
op, app = attempt.op, attempt.app
|
|
15
|
+
effect = agent._effect(op, attempt.element, app, attempt.text, agent._app_name(turn.snapshot), turn.snapshot)
|
|
16
|
+
attempt.unknown_repeat = None # "retry" or "ask": this action repeats one whose outcome was unknown
|
|
17
|
+
attempt.held = agent._held(effect, turn.snapshot)
|
|
18
|
+
if attempt.held is not None:
|
|
19
|
+
# An action that may already have run is never sent again blind: a fresh read settles it first.
|
|
20
|
+
what = attempt.element.label[:60] if attempt.element else (app or "")
|
|
21
|
+
attempt.unknown_repeat, fresh, found = agent._recheck_unknown(op, attempt.element, attempt.held, what)
|
|
22
|
+
if attempt.unknown_repeat == "refuse":
|
|
23
|
+
turn.feedback = fresh
|
|
24
|
+
turn.history.append(f"{turn.step}.{index}: {op} {what!r} refused (its earlier outcome was unknown)")
|
|
25
|
+
agent._emit({"event": "frontier_refused", "step": turn.step, "label": "outcome_unknown"})
|
|
26
|
+
return "stop"
|
|
27
|
+
turn.snapshot, attempt.element = fresh, found
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def loops(agent, attempt, turn):
|
|
31
|
+
index = turn.index
|
|
32
|
+
op, text, app, element = attempt.op, attempt.text, attempt.app, attempt.element
|
|
33
|
+
attempt.key = (op, element.label if element else app, text)
|
|
34
|
+
# A loop is the same control, text and screen: another value or another list row is not one.
|
|
35
|
+
attempt.spot = (op, (element.locator or element.label) if element else app,
|
|
36
|
+
text if op in TYPED_OPS or op == "SCROLL_TO" else None, turn.snapshot.content_fingerprint)
|
|
37
|
+
keypad = element is not None and is_keypad_key(op, element.role, element.label)
|
|
38
|
+
if (not op.startswith("SWIPE_") and op != "DISMISS" and not keypad
|
|
39
|
+
and turn.recent.count(attempt.spot) >= LOOP_REPEATS - 1):
|
|
40
|
+
turn.feedback = (f"Refused: this is the {LOOP_REPEATS}rd time recently you {op} "
|
|
41
|
+
f"{(element.label if element else app)!r}; you are going in circles. Use a different "
|
|
42
|
+
"route: the app's search, another tab or menu, scrolling, or skip this part and move "
|
|
43
|
+
"on to the next part of the request.")
|
|
44
|
+
turn.history.append(f"{turn.step}.{index}: {op} {(element.label[:60] if element else app)!r} refused (loop)")
|
|
45
|
+
agent._emit({"event": "frontier_refused", "step": turn.step, "label": "loop"})
|
|
46
|
+
return "stop"
|
|
47
|
+
if op == "DISMISS" and agent.run_state.dismissed == (turn.snapshot.content_fingerprint, len(DISMISS_POINTS) - 1):
|
|
48
|
+
turn.feedback = ("Refused: tapping outside was tried everywhere and closed nothing. Use the overlay's "
|
|
49
|
+
"own controls (Close, Cancel, Done, Back) or choose an item in it.")
|
|
50
|
+
turn.history.append(f"{turn.step}.{index}: DISMISS refused (tried every point)")
|
|
51
|
+
agent._emit({"event": "frontier_refused", "step": turn.step, "label": "dismiss_exhausted"})
|
|
52
|
+
return "stop"
|
|
53
|
+
# A repeat is the same action on the screen it left (typing) or was made on (a tap).
|
|
54
|
+
turn.repeats = (
|
|
55
|
+
turn.repeats + 1
|
|
56
|
+
if turn.last_done and turn.last_done[0] == attempt.key
|
|
57
|
+
and turn.snapshot.content_fingerprint == (turn.last_done[2] if op in TYPED_OPS else turn.last_done[1])
|
|
58
|
+
else 0)
|
|
59
|
+
if op not in HOUSEKEEPING_OPS and (op in TYPED_OPS and turn.repeats >= 1 or turn.repeats >= 2):
|
|
60
|
+
turn.feedback = ("Refused: you just did exactly this action. Its effect is already on screen (for "
|
|
61
|
+
"typed text, see the field's value). Take the next step instead, e.g. save or confirm.")
|
|
62
|
+
turn.history.append(f"{turn.step}.{index}: repeat of the previous action refused")
|
|
63
|
+
agent._emit({"event": "frontier_refused", "step": turn.step, "label": "repeat"})
|
|
64
|
+
return "stop"
|
|
65
|
+
act_key = agent._act_key(op, element, turn.snapshot)
|
|
66
|
+
if act_key is not None and act_key in agent.run_state.acts_done:
|
|
67
|
+
before_refusal = agent.run_state.act_refused.get(act_key)
|
|
68
|
+
known = before_refusal if before_refusal is not None else {act_key[2], agent.run_state.act_left[act_key]}
|
|
69
|
+
new_look = bool(agent.run_state.act_seen[act_key] - known)
|
|
70
|
+
else:
|
|
71
|
+
new_look = True
|
|
72
|
+
if not new_look:
|
|
73
|
+
# Fails closed: the repeat waits until the run has looked somewhere the act could show.
|
|
74
|
+
template = REPEAT_ACT_FEEDBACK if act_key not in agent.run_state.act_refused else REPEAT_ACT_AGAIN
|
|
75
|
+
agent.run_state.act_refused[act_key] = frozenset(agent.run_state.act_seen[act_key] | {act_key[2]})
|
|
76
|
+
turn.feedback = template.format(label=element.label[:60], step=agent.run_state.acts_done[act_key])
|
|
77
|
+
turn.history.append(f"{turn.step}.{index}: TAP {element.label[:60]!r} refused (done before on this screen)")
|
|
78
|
+
agent._emit({"event": "frontier_refused", "step": turn.step, "label": "repeat_act"})
|
|
79
|
+
return "stop"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def requested(agent, attempt, turn):
|
|
83
|
+
index = turn.index
|
|
84
|
+
element = attempt.element
|
|
85
|
+
refused = guard(turn.request, attempt.op, element) if agent._contract is None else None
|
|
86
|
+
if refused:
|
|
87
|
+
turn.feedback = refused
|
|
88
|
+
turn.history.append(f"{turn.step}.{index}: TAP {element.label[:60]!r} refused (not requested)")
|
|
89
|
+
agent._emit({"event": "frontier_refused", "step": turn.step, "label": element.label[:120]})
|
|
90
|
+
return "stop"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def refresh(agent, attempt, turn):
|
|
94
|
+
index = turn.index
|
|
95
|
+
attempt.refresh_ms = 0
|
|
96
|
+
if attempt.element is not None and index == 0:
|
|
97
|
+
# The model took seconds: act on the screen as it is now, or the driver refuses a stale read (splitpay-001).
|
|
98
|
+
t_refresh = time.monotonic()
|
|
99
|
+
fresh, reused = agent._refreshed(turn.snapshot)
|
|
100
|
+
turn.counts["reused"] += reused
|
|
101
|
+
attempt.refresh_ms = agent._spend("refresh", t_refresh)
|
|
102
|
+
moved = agent._find(fresh, attempt.element.label, attempt.element.role, attempt.element.locator)
|
|
103
|
+
if moved is not None:
|
|
104
|
+
turn.snapshot, attempt.element = fresh, moved
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def results_still_moving(agent, attempt, turn):
|
|
108
|
+
index = turn.index
|
|
109
|
+
op = attempt.op
|
|
110
|
+
if (op in ("TAP", "LONG_PRESS", "TAP_XY") and agent.run_state.submitted_at is not None
|
|
111
|
+
and time.monotonic() - agent.run_state.submitted_at < SUBMIT_WINDOW_SECONDS):
|
|
112
|
+
# Results of a search just submitted may still be moving: tap only on two agreeing reads.
|
|
113
|
+
t_still = time.monotonic()
|
|
114
|
+
still, moved_to = agent._still_after_submit(attempt.element)
|
|
115
|
+
agent._spend("settle", t_still)
|
|
116
|
+
if still is None:
|
|
117
|
+
turn.feedback = ("The search results were still changing, so Mobster did not tap. Look at the "
|
|
118
|
+
"screen again and choose from what it shows now.")
|
|
119
|
+
turn.history.append(f"{turn.step}.{index}: {op} held: results still changing after the search")
|
|
120
|
+
agent._emit({"event": "frontier_chunk_stop", "step": turn.step, "index": index,
|
|
121
|
+
"reason": "results_moving"})
|
|
122
|
+
turn.snapshot, turn.unproven = agent._read_once(), False
|
|
123
|
+
return "stop"
|
|
124
|
+
turn.snapshot = still
|
|
125
|
+
if attempt.element is not None:
|
|
126
|
+
if moved_to is None:
|
|
127
|
+
agent._emit({"event": "frontier_chunk_stop", "step": turn.step, "index": index,
|
|
128
|
+
"reason": "target_missing", "wanted": (attempt.element.label or "")[:80]})
|
|
129
|
+
turn.history.append(f"{turn.step}.{index}: {op} target {attempt.element.label[:60]!r} gone once the "
|
|
130
|
+
"results settled; stopped the sequence")
|
|
131
|
+
return "stop"
|
|
132
|
+
attempt.element = moved_to
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""The stages for the passcode keypad, a skill, and a point or gesture on the screen."""
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
from ...agent_hooks import RESUME_AFTER_SECONDS, GuardVerdict
|
|
7
|
+
from ...task_policy import springboard_keypad
|
|
8
|
+
from ...wda.point_gestures import GESTURE_OPS, validate_gesture_request
|
|
9
|
+
from ..act import LEAVING_OPS
|
|
10
|
+
from ..interrupts import Where, check
|
|
11
|
+
from ..protocol import ELEMENT_OPS
|
|
12
|
+
from ..safety import KEYPAD_REFUSAL, PHONE_LOCKED, SAME_FAILURES_TO_CHECK, GuardStop, declined_result
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def keypad(agent, attempt, turn):
|
|
16
|
+
index = turn.index
|
|
17
|
+
op = attempt.op
|
|
18
|
+
if op in ELEMENT_OPS or op == "TAP_XY" or op in GESTURE_OPS or op in agent._skill_ops:
|
|
19
|
+
if springboard_keypad(turn.snapshot):
|
|
20
|
+
# The lock screen's keypad is never the model's (B2): the guard may unlock or stop.
|
|
21
|
+
turn.keypad_refusals += 1
|
|
22
|
+
turn.feedback = KEYPAD_REFUSAL
|
|
23
|
+
turn.history.append(f"{turn.step}.{index}: {op} refused (passcode screen)")
|
|
24
|
+
agent._emit({"event": "frontier_refused", "step": turn.step, "label": "passcode_keypad"})
|
|
25
|
+
verdict = agent._guard_check("lock_suspected", turn.history)
|
|
26
|
+
if verdict is not None and verdict.state == "unlocked":
|
|
27
|
+
turn.keypad_refusals, turn.snapshot, turn.unproven = 0, agent._observe(), False
|
|
28
|
+
elif agent.guard is None or turn.keypad_refusals >= SAME_FAILURES_TO_CHECK:
|
|
29
|
+
raise GuardStop(GuardVerdict("stop", "phone_locked", PHONE_LOCKED + (
|
|
30
|
+
"" if turn.actions else " No action was taken.")))
|
|
31
|
+
return "stop"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def skill(agent, attempt, turn):
|
|
35
|
+
index = turn.index
|
|
36
|
+
if attempt.op in LEAVING_OPS:
|
|
37
|
+
agent._reveal_found(turn)
|
|
38
|
+
op = attempt.op
|
|
39
|
+
chosen = agent._skill_ops.get(op)
|
|
40
|
+
if chosen is not None and op == "OPEN_URL" and attempt.act.app and attempt.act.app not in agent.apps:
|
|
41
|
+
# A web page opens in a listed app only, else in the browser on screen or the default one.
|
|
42
|
+
attempt.act = dataclasses.replace(attempt.act, app=None)
|
|
43
|
+
if chosen is not None:
|
|
44
|
+
if turn.session is not None:
|
|
45
|
+
turn.session.mark_action()
|
|
46
|
+
ended, said_back, turn.snapshot, changed, waited = agent._run_skill(
|
|
47
|
+
chosen, attempt.act, index, turn.aliases, turn.snapshot, turn.request, turn.step, turn.history, turn.after)
|
|
48
|
+
turn.started += waited
|
|
49
|
+
agent._waited(waited)
|
|
50
|
+
turn.unproven = False
|
|
51
|
+
if ended is None and turn.snapshot is not None:
|
|
52
|
+
# A link can land in any app: the app in front is checked before anything there is read or done.
|
|
53
|
+
agent._check_app(turn.snapshot)
|
|
54
|
+
if ended is not None and "redirect" in ended:
|
|
55
|
+
instruction = ended["redirect"]
|
|
56
|
+
turn.request = f"{turn.request}\n\nThe user's later instruction: {instruction}"
|
|
57
|
+
turn.feedback = f"The user declined {op} and asked instead: {instruction!r}. Do that now."
|
|
58
|
+
turn.history.append(f"{turn.step}.{index}: {op} declined; user redirected")
|
|
59
|
+
return "stop"
|
|
60
|
+
if ended is not None:
|
|
61
|
+
turn.result = ended
|
|
62
|
+
return "end"
|
|
63
|
+
turn.feedback = said_back or ""
|
|
64
|
+
if changed:
|
|
65
|
+
turn.actions += 1
|
|
66
|
+
agent._actions = turn.actions
|
|
67
|
+
turn.acted = True
|
|
68
|
+
return "stop" # a skill's result is looked at before anything else is done
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def gesture_points(agent, attempt, turn):
|
|
72
|
+
index = turn.index
|
|
73
|
+
op = attempt.op
|
|
74
|
+
if op in GESTURE_OPS:
|
|
75
|
+
# One gesture, on the screen and picture the model chose its points from, with nothing chained after it.
|
|
76
|
+
try:
|
|
77
|
+
attempt.point = validate_gesture_request(GESTURE_OPS[op], json.loads(attempt.text or ""))
|
|
78
|
+
turn.snapshot = agent.gesture_screen(turn.snapshot, turn.image, attempt.point, turn.request)
|
|
79
|
+
except (TypeError, ValueError) as error:
|
|
80
|
+
if check(agent, turn, Where.WAITED) is not None:
|
|
81
|
+
return "end"
|
|
82
|
+
turn.feedback = str(error)
|
|
83
|
+
turn.history.append(f"{turn.step}.{index}: {op} refused")
|
|
84
|
+
agent._emit({"event": "frontier_refused", "step": turn.step, "label": op.lower(),
|
|
85
|
+
"detail": turn.feedback[:160]})
|
|
86
|
+
return "stop"
|
|
87
|
+
del turn.chunk[index + 1:]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def point_approval(agent, attempt, turn):
|
|
91
|
+
index = turn.index
|
|
92
|
+
op = attempt.op
|
|
93
|
+
if op == "TAP_XY" or op in GESTURE_OPS:
|
|
94
|
+
if op == "TAP_XY":
|
|
95
|
+
if agent._image_mode == "tree" and turn.image is None:
|
|
96
|
+
attempt.point, why = None, "Read a screenshot before choosing screen points."
|
|
97
|
+
else:
|
|
98
|
+
attempt.point, why = agent._tap_xy(turn.request, attempt.act, turn.aliases, turn.snapshot)
|
|
99
|
+
if why:
|
|
100
|
+
turn.feedback = why
|
|
101
|
+
turn.history.append(f"{turn.step}.{index}: TAP_XY {(attempt.text or '')[:40]!r} refused")
|
|
102
|
+
agent._emit({"event": "frontier_refused", "step": turn.step, "label": "tap_xy",
|
|
103
|
+
"detail": why[:160]})
|
|
104
|
+
return "stop"
|
|
105
|
+
named = " ".join((attempt.text or "").split())[:40]
|
|
106
|
+
attempt.app = f"{named} at {attempt.point[0] * 100:.0f},{attempt.point[1] * 100:.0f}"
|
|
107
|
+
else:
|
|
108
|
+
named = attempt.app = attempt.point.label
|
|
109
|
+
attempt.text = None
|
|
110
|
+
verdict, waited, asked = agent._point_approval(
|
|
111
|
+
attempt.point.start if op in GESTURE_OPS else attempt.point, turn.snapshot, turn.request, turn.chain_typed,
|
|
112
|
+
turn.step, turn.session, gesture=attempt.point if op in GESTURE_OPS else None)
|
|
113
|
+
turn.started += waited # waiting for the user never spends the task's time
|
|
114
|
+
agent._waited(waited)
|
|
115
|
+
if verdict is None and asked and check(agent, turn, Where.WAITED) is not None:
|
|
116
|
+
return "end"
|
|
117
|
+
if verdict is None and asked:
|
|
118
|
+
# The person approved the spot as the screen was: one that moved since is not tapped.
|
|
119
|
+
if waited >= RESUME_AFTER_SECONDS:
|
|
120
|
+
agent._guard_check("resume", turn.history)
|
|
121
|
+
if op in GESTURE_OPS:
|
|
122
|
+
try:
|
|
123
|
+
fresh = agent.gesture_screen(turn.snapshot, turn.image, attempt.point, turn.request)
|
|
124
|
+
matched = True
|
|
125
|
+
except ValueError:
|
|
126
|
+
fresh, matched = turn.snapshot, False
|
|
127
|
+
else:
|
|
128
|
+
fresh = agent._observe()
|
|
129
|
+
matched = fresh.content_fingerprint == turn.snapshot.content_fingerprint
|
|
130
|
+
if check(agent, turn, Where.WAITED) is not None:
|
|
131
|
+
return "end"
|
|
132
|
+
if not matched:
|
|
133
|
+
turn.feedback = "The screen changed while Mobster waited for your OK: look again."
|
|
134
|
+
turn.history.append(f"{turn.step}.{index}: {op} {named!r} not "
|
|
135
|
+
+ ("tapped" if op == "TAP_XY" else "done") + " (the screen changed)")
|
|
136
|
+
turn.snapshot = fresh
|
|
137
|
+
return "stop"
|
|
138
|
+
turn.snapshot = fresh
|
|
139
|
+
if verdict is not None and verdict.startswith(("refused:", "blocked:")):
|
|
140
|
+
turn.feedback = (f"Refused: {verdict.split(':', 1)[1]}, or finish with what you found (BLOCKED if "
|
|
141
|
+
"the request needs this).")
|
|
142
|
+
turn.history.append(f"{turn.step}.{index}: TAP_XY {named!r} refused (needs the user's OK)")
|
|
143
|
+
agent._emit({"event": "frontier_refused", "step": turn.step, "label": "needs_approval"})
|
|
144
|
+
return "stop"
|
|
145
|
+
if verdict is not None and verdict.startswith("redirected:"):
|
|
146
|
+
agent.run_state.asked = "redirected"
|
|
147
|
+
instruction = " ".join(verdict.split(":", 1)[1].split())[:500]
|
|
148
|
+
turn.request = f"{turn.request}\n\nThe user's later instruction: {instruction}"
|
|
149
|
+
turn.feedback = (f"The user declined the tap at that spot and asked instead: {instruction!r}. "
|
|
150
|
+
"Do that now.")
|
|
151
|
+
turn.history.append(f"{turn.step}.{index}: TAP_XY {named!r} declined; user redirected")
|
|
152
|
+
return "stop"
|
|
153
|
+
if verdict is not None:
|
|
154
|
+
turn.result = declined_result(verdict)
|
|
155
|
+
return "end"
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""The stages that send an action to the phone and answer its failure."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from ... import contract_asks as proof_asks
|
|
6
|
+
from ...model_clients import http_detail
|
|
7
|
+
from ...wda.guards import DriverRejection
|
|
8
|
+
from ...wda.point_gestures import GESTURE_OPS
|
|
9
|
+
from ..interrupts import Where, check
|
|
10
|
+
from ..protocol import ELEMENT_OPS, TYPED_OPS
|
|
11
|
+
from ..safety import (
|
|
12
|
+
CONNECTION_LOST,
|
|
13
|
+
NOTHING_SENT,
|
|
14
|
+
SAME_FAILURES_TO_CHECK,
|
|
15
|
+
SAME_FAILURES_TO_STOP,
|
|
16
|
+
UNKNOWN_REASON,
|
|
17
|
+
GuardStop,
|
|
18
|
+
consequential,
|
|
19
|
+
failure_feedback,
|
|
20
|
+
outcome_unknown,
|
|
21
|
+
stuck_sentence,
|
|
22
|
+
unknown_advice,
|
|
23
|
+
)
|
|
24
|
+
from ..screen import names_act, reads_back
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def execute(agent, attempt, turn):
|
|
28
|
+
index = turn.index
|
|
29
|
+
op, text, app, point, held, unknown_repeat, gate = (
|
|
30
|
+
attempt.op, attempt.text, attempt.app, attempt.point, attempt.held, attempt.unknown_repeat, attempt.gate)
|
|
31
|
+
attempt.before = turn.snapshot
|
|
32
|
+
attempt.effect = agent._effect(op, attempt.element, app, text, agent._app_name(turn.snapshot), turn.snapshot)
|
|
33
|
+
attempt.before_unknown = (
|
|
34
|
+
agent._before_unknown(attempt.element, turn.snapshot) if attempt.effect is not None else None)
|
|
35
|
+
if unknown_repeat == "retry":
|
|
36
|
+
# A fresh read showed the earlier attempt did nothing: this is its one more attempt.
|
|
37
|
+
agent.run_state.effects.settle(held[0], None, effect=held[1], happened=False)
|
|
38
|
+
agent._emit({"event": "frontier_retry", "step": turn.step, "index": index, "operation": op,
|
|
39
|
+
"reason": "outcome_unknown_unchanged"})
|
|
40
|
+
attempt.t_exec = time.monotonic()
|
|
41
|
+
agent.run_state.last_receipt = None
|
|
42
|
+
if turn.session is not None:
|
|
43
|
+
turn.session.mark_action()
|
|
44
|
+
if op in GESTURE_OPS:
|
|
45
|
+
# Journaled before it is sent: after a restart the gesture counts as one that may have run.
|
|
46
|
+
if check(agent, turn, Where.WAITED) is not None:
|
|
47
|
+
return "end"
|
|
48
|
+
agent._emit({"event": "action_started", "operation": op, "target": app})
|
|
49
|
+
if check(agent, turn, Where.WAITED) is not None:
|
|
50
|
+
return "end"
|
|
51
|
+
try:
|
|
52
|
+
try:
|
|
53
|
+
attempt.before = agent._execute(op, attempt.element, app, text, turn.snapshot, point)
|
|
54
|
+
except Exception as error:
|
|
55
|
+
# Resent only when the request never ran (refused, a dropped session); never a gesture or a point.
|
|
56
|
+
if op in GESTURE_OPS or op == "TAP_XY" or not agent._recover(error) or not any(
|
|
57
|
+
mark in str(error) for mark in NOTHING_SENT):
|
|
58
|
+
raise
|
|
59
|
+
turn.snapshot = agent._observe()
|
|
60
|
+
if attempt.element is not None:
|
|
61
|
+
attempt.element = agent._find(
|
|
62
|
+
turn.snapshot, attempt.element.label, attempt.element.role, attempt.element.locator)
|
|
63
|
+
if attempt.element is None:
|
|
64
|
+
raise
|
|
65
|
+
attempt.before = agent._execute(op, attempt.element, app, text, turn.snapshot, point)
|
|
66
|
+
if op in GESTURE_OPS:
|
|
67
|
+
agent._emit({"event": "action_acknowledged", "step": turn.step, "operation": op})
|
|
68
|
+
turn.actions += 1
|
|
69
|
+
agent._actions = turn.actions
|
|
70
|
+
if attempt.commit_now:
|
|
71
|
+
agent.run_state.commits += 1
|
|
72
|
+
if unknown_repeat is not None:
|
|
73
|
+
agent.run_state.effects.resolve(held[0], None, effect=held[1])
|
|
74
|
+
turn.acted_since = turn.acted_since or names_act(op, attempt.element, text)
|
|
75
|
+
if attempt.element is not None:
|
|
76
|
+
turn.touched.append(attempt.element)
|
|
77
|
+
if op == "READ_LIST" and agent.run_state.listing:
|
|
78
|
+
turn.read_rows = list(agent.run_state.listing)
|
|
79
|
+
agent.run_state.submitted_at = time.monotonic() if op in ("TYPE_SUBMIT", "SUBMIT") else (
|
|
80
|
+
agent.run_state.submitted_at if op not in ("TAP", "LONG_PRESS", "TAP_XY") else None)
|
|
81
|
+
if turn.session is not None:
|
|
82
|
+
# Opening the app already in front is no progress (P1-1).
|
|
83
|
+
turn.session.on_acted(noop=op == "LAUNCH_APP" and app == getattr(turn.snapshot, "bundle_id", None))
|
|
84
|
+
if agent._contract is not None:
|
|
85
|
+
where = agent._app_name(attempt.before)
|
|
86
|
+
agent._contract.record_action(where, op, getattr(attempt.element, "label", "") or "")
|
|
87
|
+
if op in TYPED_OPS and text:
|
|
88
|
+
agent._contract.record_typed(where, attempt.element, text, turn.step)
|
|
89
|
+
turn.chain_typed.append(text)
|
|
90
|
+
if gate is not None and gate.item is not None:
|
|
91
|
+
agent._contract.committed(gate, attempt.element, attempt.before, where, turn.step)
|
|
92
|
+
if op == "READ_LIST" and agent.run_state.listing:
|
|
93
|
+
agent._contract.saw_lines(where, turn.step, agent.run_state.listing)
|
|
94
|
+
turn.acted = turn.acted or op in ELEMENT_OPS or op == "TAP_XY" or op in GESTURE_OPS
|
|
95
|
+
if agent.run_state.macro_feedback:
|
|
96
|
+
turn.feedback, agent.run_state.macro_feedback = agent.run_state.macro_feedback, None
|
|
97
|
+
except GuardStop:
|
|
98
|
+
raise
|
|
99
|
+
except Exception as error:
|
|
100
|
+
attempt.error = error
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def failure(agent, attempt, turn):
|
|
104
|
+
error = attempt.error
|
|
105
|
+
if error is None:
|
|
106
|
+
return None
|
|
107
|
+
index = turn.index
|
|
108
|
+
op, text, app, element, gate, before_unknown, effect = (
|
|
109
|
+
attempt.op, attempt.text, attempt.app, attempt.element, attempt.gate, attempt.before_unknown, attempt.effect)
|
|
110
|
+
if op in GESTURE_OPS and not (isinstance(error, DriverRejection) and error.code in error.PRE_DISPATCH):
|
|
111
|
+
kind = GESTURE_OPS[op]
|
|
112
|
+
turn.result = {"status": "blocked", "answer": None, "code": "unknown_outcome",
|
|
113
|
+
"reason": f"The {kind} outcome is unknown. Inspect the phone before starting another "
|
|
114
|
+
"task; it was not retried."}
|
|
115
|
+
agent._emit({"event": "frontier_failed", "step": turn.step, "index": index, "operation": op,
|
|
116
|
+
"error": f"{kind} outcome unknown", "outcome": "unknown"})
|
|
117
|
+
return "end"
|
|
118
|
+
# A request on a dropped session never ran: its outcome is known.
|
|
119
|
+
lost = agent.run_state.recoveries and any(name in str(error) for name in CONNECTION_LOST if name != "StaleSession")
|
|
120
|
+
# A tap at a point has no control to read back: any failure past dispatch is held as unknown.
|
|
121
|
+
unknown = bool(lost) or outcome_unknown(error, op) or (
|
|
122
|
+
op == "TAP_XY" and not (isinstance(error, DriverRejection) and error.code in error.PRE_DISPATCH))
|
|
123
|
+
if unknown and effect is not None:
|
|
124
|
+
agent.run_state.effects.record_outcome(effect[0], None, outcome="unknown", effect=effect[1],
|
|
125
|
+
context=before_unknown)
|
|
126
|
+
if unknown and gate is not None and gate.item is not None and proof_asks.asks(gate.item):
|
|
127
|
+
# Any control of this act, on any screen, now asks with the warning, in every mode.
|
|
128
|
+
agent.run_state.held_items[gate.item.id] = UNKNOWN_REASON
|
|
129
|
+
turn.feedback = (("The connection to the phone dropped during this action and was restored: it may or "
|
|
130
|
+
"may not have happened. " + unknown_advice(op)) if lost
|
|
131
|
+
else failure_feedback(op, element, text, error))
|
|
132
|
+
detail = http_detail(error)
|
|
133
|
+
what = element.label[:60] if element else (app or "")
|
|
134
|
+
# The line names the target and the status: a bare one repeated a failed launch fifty times (B2).
|
|
135
|
+
turn.history.append(f"{turn.step}.{index}: {op} {what!r} failed ({detail})")
|
|
136
|
+
agent._spend("exec", attempt.t_exec)
|
|
137
|
+
agent._emit({"event": "frontier_failed", "step": turn.step, "index": index, "operation": op,
|
|
138
|
+
"error": f"{type(error).__name__}: {str(error)[:160]}",
|
|
139
|
+
"outcome": "unknown" if unknown else "failed",
|
|
140
|
+
# A picked-up run holds this act too (checkpoints.held_acts).
|
|
141
|
+
**({"held_act": gate.item.act} if unknown and gate is not None and gate.item is not None
|
|
142
|
+
and proof_asks.asks(gate.item) else {})})
|
|
143
|
+
t_observe = time.monotonic()
|
|
144
|
+
turn.snapshot, turn.unproven = agent._observe(), False
|
|
145
|
+
agent._spend("observe", t_observe)
|
|
146
|
+
if unknown and effect is not None and element is not None:
|
|
147
|
+
# The look after it: a screen that moved on, or a control that changed, says it happened.
|
|
148
|
+
if not agent._unchanged(before_unknown, element, turn.snapshot)[0]:
|
|
149
|
+
agent.run_state.effects.settle(effect[0], None, effect=effect[1], happened=True)
|
|
150
|
+
turn.feedback += (" The screen changed after it, so Mobster counts it as done and won't send it "
|
|
151
|
+
"again.")
|
|
152
|
+
elif consequential(op, element, turn.snapshot):
|
|
153
|
+
turn.feedback += " The screen looks unchanged; sending it again needs the user's OK."
|
|
154
|
+
else:
|
|
155
|
+
turn.feedback += (" The screen looks unchanged, so it probably didn't happen: if it still looks "
|
|
156
|
+
"the same, you may send it once more.")
|
|
157
|
+
if op in TYPED_OPS and text and element is not None and agent._contract is not None:
|
|
158
|
+
# Typing that timed out may have landed: a field reading it back holds the agent's text.
|
|
159
|
+
field = agent._find(turn.snapshot, element.label, element.role, element.locator)
|
|
160
|
+
if field is not None and field.editable and reads_back(field.value or "", text):
|
|
161
|
+
agent._contract.record_typed(agent._app_name(turn.snapshot), field, text, turn.step)
|
|
162
|
+
turn.feedback += " The field now reads back exactly the text you wrote: don't type it again."
|
|
163
|
+
same = (op, (element.locator or element.label) if element else app, text)
|
|
164
|
+
turn.failures[same] = turn.failures.get(same, 0) + 1
|
|
165
|
+
if op == "LAUNCH_APP" and detail == "HTTP 400" or turn.failures[same] >= SAME_FAILURES_TO_CHECK:
|
|
166
|
+
# iOS refuses to bring an app forward over the lock screen or a passcode sheet.
|
|
167
|
+
verdict = agent._guard_check("launch_failed" if op == "LAUNCH_APP" else "lock_suspected",
|
|
168
|
+
turn.history)
|
|
169
|
+
if verdict is not None and verdict.state == "unlocked":
|
|
170
|
+
turn.failures.clear()
|
|
171
|
+
turn.snapshot = agent._observe()
|
|
172
|
+
if turn.failures.get(same, 0) >= SAME_FAILURES_TO_STOP:
|
|
173
|
+
name = agent.apps.get(app, app) if op == "LAUNCH_APP" else what
|
|
174
|
+
sentence = stuck_sentence(op, name, detail, turn.actions)
|
|
175
|
+
turn.result = {"status": "blocked", "answer": None, "reason": sentence}
|
|
176
|
+
return "end"
|
|
177
|
+
return "stop"
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""The two records a run keeps: Turn, what the turn loop and its actions share, and RunState, what the run has done."""
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import threading
|
|
5
|
+
from collections import deque
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from ..effect_ledger import EffectLedger
|
|
9
|
+
from ..harness_api import InitialState
|
|
10
|
+
from ..state import Element, Snapshot
|
|
11
|
+
from .actions import Action
|
|
12
|
+
from .screen import Provenance, _Verify
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# The turn loop's locals that the per-action step shares; slots turn a misspelt name into an AttributeError.
|
|
16
|
+
@dataclasses.dataclass(slots=True, kw_only=True)
|
|
17
|
+
class Turn:
|
|
18
|
+
request: str
|
|
19
|
+
started: float
|
|
20
|
+
recent: deque
|
|
21
|
+
session: Any # a longform session; the engine does not import longform
|
|
22
|
+
data_json: bool
|
|
23
|
+
stopped: dict
|
|
24
|
+
acted: bool = False
|
|
25
|
+
acted_since: bool = False
|
|
26
|
+
actions: int = 0
|
|
27
|
+
after: str | None = None
|
|
28
|
+
aliases: dict[str, Element] = dataclasses.field(default_factory=dict)
|
|
29
|
+
calls: int = 0
|
|
30
|
+
chain_typed: list[str] = dataclasses.field(default_factory=list)
|
|
31
|
+
checked_front: bool = False
|
|
32
|
+
chunk: list[Action] = dataclasses.field(default_factory=list)
|
|
33
|
+
counts: dict[str, int] = dataclasses.field(
|
|
34
|
+
default_factory=lambda: {"reused": 0, "verified": 0, "verify_changed": 0})
|
|
35
|
+
covered: int = 0
|
|
36
|
+
failures: dict[tuple, int] = dataclasses.field(default_factory=dict)
|
|
37
|
+
feedback: str = ""
|
|
38
|
+
finished: bool = False
|
|
39
|
+
history: list[str] = dataclasses.field(default_factory=list)
|
|
40
|
+
idle_waits: int = 0
|
|
41
|
+
image: dict | None = None
|
|
42
|
+
index: int = 0
|
|
43
|
+
keypad_refusals: int = 0
|
|
44
|
+
last_done: tuple | None = None
|
|
45
|
+
out: dict = dataclasses.field(default_factory=dict)
|
|
46
|
+
read_rows: list[str] | None = None
|
|
47
|
+
refusals: dict[str, int] = dataclasses.field(default_factory=dict)
|
|
48
|
+
repeats: int = 0
|
|
49
|
+
request_checked: bool = False
|
|
50
|
+
reserve: float = 0.0
|
|
51
|
+
result: dict = dataclasses.field(default_factory=lambda: {"status": "max_steps", "answer": None})
|
|
52
|
+
snapshot: Snapshot | None = None
|
|
53
|
+
spent: float | None = None
|
|
54
|
+
step: int = 0
|
|
55
|
+
touched: list[Element] = dataclasses.field(default_factory=list)
|
|
56
|
+
turn_rows: set[str] | None = None
|
|
57
|
+
turn_screen: Snapshot | None = None
|
|
58
|
+
unproven: bool = False
|
|
59
|
+
untaken: tuple[str, str] | None = None
|
|
60
|
+
plan: str = ""
|
|
61
|
+
notes: list[str] = dataclasses.field(default_factory=list)
|
|
62
|
+
max_actions: int = 0
|
|
63
|
+
source_reads: tuple = (None, None)
|
|
64
|
+
compiled: list = dataclasses.field(default_factory=list)
|
|
65
|
+
worker: threading.Thread | None = None
|
|
66
|
+
pending: bool = False
|
|
67
|
+
unpriced: str = ""
|
|
68
|
+
unrunnable: int = 0
|
|
69
|
+
final: str | None = None
|
|
70
|
+
capped: bool = False
|
|
71
|
+
operations: tuple[str, ...] = ()
|
|
72
|
+
lines: list[str] = dataclasses.field(default_factory=list)
|
|
73
|
+
prep_ms: int = 0
|
|
74
|
+
messages: list | None = None
|
|
75
|
+
verify: _Verify | None = None
|
|
76
|
+
programmed: bool = False
|
|
77
|
+
proposed: list[Action] = dataclasses.field(default_factory=list)
|
|
78
|
+
unrun: str | None = None
|
|
79
|
+
usage: dict = dataclasses.field(default_factory=dict)
|
|
80
|
+
latency_ms: int = 0
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# What one run has done so far; run() starts a new one, so nothing carries over from an earlier run.
|
|
84
|
+
@dataclasses.dataclass(slots=True, kw_only=True)
|
|
85
|
+
class RunState:
|
|
86
|
+
started: float
|
|
87
|
+
initial: InitialState | None = None
|
|
88
|
+
held_acts: frozenset = frozenset()
|
|
89
|
+
notes: list[str] = dataclasses.field(default_factory=list)
|
|
90
|
+
plan: str = ""
|
|
91
|
+
compile_worker: threading.Thread | None = None
|
|
92
|
+
calls: int = 0
|
|
93
|
+
timing: dict[str, float] = dataclasses.field(default_factory=dict)
|
|
94
|
+
cost_offset: float = 0.0
|
|
95
|
+
recovery_spent: float = 0.0
|
|
96
|
+
stall_spent: float = 0.0
|
|
97
|
+
unlocks: int = 0
|
|
98
|
+
secrets: set[str] = dataclasses.field(default_factory=set)
|
|
99
|
+
secret_rects: list[tuple] = dataclasses.field(default_factory=list)
|
|
100
|
+
skill_images: list[tuple] = dataclasses.field(default_factory=list)
|
|
101
|
+
imaged_app: str | None = None
|
|
102
|
+
blind: int = 0
|
|
103
|
+
image_why: str = "off"
|
|
104
|
+
cards: int = 0
|
|
105
|
+
commits: int = 0
|
|
106
|
+
held_items: dict[str, str] = dataclasses.field(default_factory=dict)
|
|
107
|
+
injected: bool = False
|
|
108
|
+
ask_reason: str | None = None
|
|
109
|
+
acting_as: str | None = None
|
|
110
|
+
media_checked: bool | None = None # a commit_check preview's verdict on the commit's screen; None: none asked
|
|
111
|
+
approved_send: dict | None = None
|
|
112
|
+
declined_on: Snapshot | None = None
|
|
113
|
+
revealed: int | None = None # the turn whose recorded values were checked for a hidden row (_reveal_found)
|
|
114
|
+
redirect: tuple[str, str] | None = None
|
|
115
|
+
part: Any = None # a learned.parts.PartRun; the engine does not import learned
|
|
116
|
+
dialog_checked: tuple | None = None
|
|
117
|
+
battery_pause: bool = False
|
|
118
|
+
submitted_at: float | None = None
|
|
119
|
+
dismissed: tuple = (None, 0)
|
|
120
|
+
receipts: dict = dataclasses.field(default_factory=dict)
|
|
121
|
+
recoveries: int = 0
|
|
122
|
+
last_receipt: dict | None = None
|
|
123
|
+
acts_done: dict = dataclasses.field(default_factory=dict)
|
|
124
|
+
act_left: dict = dataclasses.field(default_factory=dict)
|
|
125
|
+
act_seen: dict = dataclasses.field(default_factory=dict)
|
|
126
|
+
act_refused: dict = dataclasses.field(default_factory=dict)
|
|
127
|
+
effects: EffectLedger = dataclasses.field(default_factory=EffectLedger)
|
|
128
|
+
timed_out_reads: int = 0
|
|
129
|
+
relaunches: int = 0
|
|
130
|
+
read_bundle: str = ""
|
|
131
|
+
start_resets: dict = dataclasses.field(default_factory=dict)
|
|
132
|
+
fresh_launch: tuple | None = None
|
|
133
|
+
listing: list | None = None
|
|
134
|
+
macro_feedback: str | None = None
|
|
135
|
+
list_read: tuple | None = None
|
|
136
|
+
passed: list[str] = dataclasses.field(default_factory=list)
|
|
137
|
+
turn_extra: str = ""
|
|
138
|
+
steered: list = dataclasses.field(default_factory=list)
|
|
139
|
+
asked: str | None = None
|
|
140
|
+
turn_log: list[str] = dataclasses.field(default_factory=list)
|
|
141
|
+
turn_notes: dict[int, list[str]] = dataclasses.field(default_factory=dict)
|
|
142
|
+
turn_marks: dict[int, list[str]] = dataclasses.field(default_factory=dict)
|
|
143
|
+
turn_plans: dict[int, str] = dataclasses.field(default_factory=dict)
|
|
144
|
+
turn_reads: dict[int, str] = dataclasses.field(default_factory=dict)
|
|
145
|
+
notes_before: list[str] = dataclasses.field(default_factory=list)
|
|
146
|
+
provenance: Provenance | None = None
|
|
147
|
+
readback: bool = False
|
|
148
|
+
kept: bool = False
|
|
149
|
+
lists: dict = dataclasses.field(default_factory=dict)
|
|
150
|
+
system: str = ""
|
|
151
|
+
stable_extra: str = ""
|