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,444 @@
|
|
|
1
|
+
"""The pre-registered task suite (MobsterBench-iOS v1), frozen by its hash in manifest.json."""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
from dataclasses import dataclass, fields, is_dataclass
|
|
6
|
+
|
|
7
|
+
from .checks import (
|
|
8
|
+
Abstains,
|
|
9
|
+
ActedAtLeast,
|
|
10
|
+
AnswerIs,
|
|
11
|
+
Captured,
|
|
12
|
+
Claimed,
|
|
13
|
+
Fixture,
|
|
14
|
+
FixtureIntact,
|
|
15
|
+
InApp,
|
|
16
|
+
ItemLabels,
|
|
17
|
+
ItemSet,
|
|
18
|
+
Literal,
|
|
19
|
+
OnScreen,
|
|
20
|
+
Shows,
|
|
21
|
+
Truth,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
SUITE_NAME = "MobsterBench-iOS"
|
|
25
|
+
SUITE_VERSION = "1.0"
|
|
26
|
+
|
|
27
|
+
CATEGORIES = ("navigation", "retrieval", "settings_state", "text_entry", "multi_app", "web",
|
|
28
|
+
"scroll", "visual")
|
|
29
|
+
|
|
30
|
+
# Safety classes. None of them persists a change to user data or settings.
|
|
31
|
+
READ_ONLY = "read_only" # observe and navigate only
|
|
32
|
+
READ_ONLY_HISTORY = "read_only_history" # also leaves local history (Safari/Maps recents, search)
|
|
33
|
+
REVERSIBLE_RESET = "reversible_reset" # transient UI state (a search field, Calculator display)
|
|
34
|
+
SAFETY_CLASSES = (READ_ONLY, READ_ONLY_HISTORY, REVERSIBLE_RESET)
|
|
35
|
+
|
|
36
|
+
BUNDLES = {
|
|
37
|
+
"settings": "com.apple.Preferences", "safari": "com.apple.mobilesafari",
|
|
38
|
+
"notes": "com.apple.mobilenotes", "reminders": "com.apple.reminders",
|
|
39
|
+
"calendar": "com.apple.mobilecal", "contacts": "com.apple.MobileAddressBook",
|
|
40
|
+
"files": "com.apple.DocumentsApp", "photos": "com.apple.mobileslideshow",
|
|
41
|
+
"maps": "com.apple.Maps", "clock": "com.apple.mobiletimer", "calculator": "com.apple.calculator",
|
|
42
|
+
}
|
|
43
|
+
SETTINGS, SAFARI = BUNDLES["settings"], BUNDLES["safari"]
|
|
44
|
+
WIKI = "https://en.m.wikipedia.org/wiki/"
|
|
45
|
+
|
|
46
|
+
# Well-known benchmark task types each category mirrors (closest analogue, not a port).
|
|
47
|
+
MIRRORS = {
|
|
48
|
+
"navigation": ("AndroidLab operation tasks (navigate-to-screen)", "iOSWorld Settings navigation",
|
|
49
|
+
"MobileAgentBench open-screen tasks"),
|
|
50
|
+
"retrieval": ("AndroidLab query tasks", "SPA-Bench single-app information retrieval"),
|
|
51
|
+
"settings_state": ("AndroidWorld System* state tasks (read-only variant)", "AndroidLab Settings queries"),
|
|
52
|
+
"text_entry": ("AndroidWorld search/typing sub-goals", "MobileAgentBench search tasks"),
|
|
53
|
+
"multi_app": ("SPA-Bench cross-app tasks", "AndroidWorld multi-app information transfer (read-only)"),
|
|
54
|
+
"web": ("WebArena/Mind2Web information seeking (mobile Safari)", "SPA-Bench web tasks"),
|
|
55
|
+
"scroll": ("AndroidLens long-horizon scrolling", "iOSWorld scroll-to-target"),
|
|
56
|
+
"visual": ("VisualWebArena visual predicates", "AndroidWorld batch tasks (dry-run visual variant)"),
|
|
57
|
+
"abstention": ("AndroidLab infeasible tasks",),
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
BUDGETS = { # (max steps, max seconds) — identical for every agent
|
|
61
|
+
"navigation": (15, 90), "retrieval": (20, 120), "settings_state": (20, 120), "text_entry": (20, 150),
|
|
62
|
+
"multi_app": (35, 300), "web": (25, 180), "scroll": (25, 180), "visual": (80, 480),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass(frozen=True)
|
|
67
|
+
class Task:
|
|
68
|
+
id: str
|
|
69
|
+
category: str
|
|
70
|
+
apps: tuple # catalog ids; the first is the start app
|
|
71
|
+
goal: str
|
|
72
|
+
checks: tuple
|
|
73
|
+
safety: str = READ_ONLY
|
|
74
|
+
answer: tuple = () # ((field, "string" | "string_list" | "labels"), ...)
|
|
75
|
+
start_url: str = ""
|
|
76
|
+
fixtures: tuple = ()
|
|
77
|
+
allow: tuple = () # extra permissions for the safety monitor: "text_entry", "calculator_keys"
|
|
78
|
+
abstention: bool = False
|
|
79
|
+
dry_run: bool = False
|
|
80
|
+
tags: tuple = ()
|
|
81
|
+
steps: int = 0
|
|
82
|
+
seconds: float = 0
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def bundle(self):
|
|
86
|
+
return BUNDLES[self.apps[0]]
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def bundles(self):
|
|
90
|
+
return tuple(BUNDLES[app] for app in self.apps)
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def max_steps(self):
|
|
94
|
+
return self.steps or BUDGETS[self.category][0]
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def max_seconds(self):
|
|
98
|
+
return self.seconds or BUDGETS[self.category][1]
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def mirrors(self):
|
|
102
|
+
return MIRRORS[self.category] + (MIRRORS["abstention"] if self.abstention else ())
|
|
103
|
+
|
|
104
|
+
def answer_schema(self):
|
|
105
|
+
"""The answer fields, as Mobster's output_schema."""
|
|
106
|
+
if not self.answer:
|
|
107
|
+
return None
|
|
108
|
+
types = {"string": {"type": "string"},
|
|
109
|
+
"string_list": {"type": "array", "items": {"type": "string"}, "maxItems": 100},
|
|
110
|
+
"labels": {"type": "array", "items": {
|
|
111
|
+
"type": "object", "properties": {"file": {"type": "string"}, "label": {"type": "string"}},
|
|
112
|
+
"required": ["file", "label"], "additionalProperties": False}, "maxItems": 100}}
|
|
113
|
+
return {"type": "object", "properties": {name: types[kind] for name, kind in self.answer},
|
|
114
|
+
"required": [name for name, _ in self.answer], "additionalProperties": False}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _t(id, category, apps, goal, checks, **kw):
|
|
118
|
+
return Task(id=id, category=category, apps=tuple(apps), goal=goal, checks=tuple(checks), **kw)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
NO_CHANGE = " Do not change any setting."
|
|
122
|
+
LOOK_ONLY = " Only look; do not open, favorite, share, edit or delete anything."
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _nav(id, title_key, goal, *, category="navigation", min_actions=1, tags=()):
|
|
126
|
+
return _t(id, category, ["settings"], goal + NO_CHANGE,
|
|
127
|
+
[Claimed(), ActedAtLeast(min_actions), InApp(SETTINGS), OnScreen(SETTINGS, Truth(title_key))],
|
|
128
|
+
tags=tags)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _answer(id, category, apps, goal, field, expect, *, mode="text", alternatives=(), extra=(),
|
|
132
|
+
start_url="", fixtures=(), safety=READ_ONLY, allow=(), min_actions=0, tags=()):
|
|
133
|
+
checks = [Claimed(), AnswerIs(field, expect, mode, tuple(alternatives)), *extra]
|
|
134
|
+
if min_actions:
|
|
135
|
+
checks.insert(1, ActedAtLeast(min_actions))
|
|
136
|
+
return _t(id, category, apps, goal, checks, answer=((field, "string"),), start_url=start_url,
|
|
137
|
+
fixtures=tuple(fixtures), safety=safety, allow=tuple(allow), tags=tuple(tags))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _web(id, goal, field, expect, start, *, category="web", mode="text", alternatives=(), min_actions=0,
|
|
141
|
+
shows=None, tags=()):
|
|
142
|
+
extra = [InApp(SAFARI)] + ([Shows(SAFARI, shows)] if shows else [])
|
|
143
|
+
return _answer(id, category, ["safari"], goal, field, expect, mode=mode, alternatives=alternatives,
|
|
144
|
+
extra=extra, start_url=start, safety=READ_ONLY_HISTORY,
|
|
145
|
+
allow=("text_entry",) if min_actions else (), min_actions=min_actions, tags=tags)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _abstain(id, category, apps, goal, field, *, start_url="", safety=READ_ONLY):
|
|
149
|
+
return _t(id, category, apps, goal, [Abstains()], answer=((field, "string"),), start_url=start_url,
|
|
150
|
+
safety=safety, abstention=True)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def build_suite():
|
|
154
|
+
s = SETTINGS
|
|
155
|
+
tasks = [
|
|
156
|
+
# ------------------------------------------------------------ navigation (10)
|
|
157
|
+
_nav("nav.accessibility", "title.accessibility", "In Settings, open the Accessibility screen."),
|
|
158
|
+
_nav("nav.keyboards", "title.keyboards", "In Settings, open General, then Keyboard.", min_actions=2),
|
|
159
|
+
_nav("nav.location_services", "title.location_services",
|
|
160
|
+
"In Settings, open Privacy & Security, then Location Services.", min_actions=2),
|
|
161
|
+
_nav("nav.display", "title.display", "In Settings, open Display & Brightness."),
|
|
162
|
+
_nav("nav.notifications", "title.notifications", "In Settings, open Notifications."),
|
|
163
|
+
_nav("nav.date_time", "title.date_time", "In Settings, open General, then Date & Time.", min_actions=2),
|
|
164
|
+
_nav("nav.about", "title.about", "In Settings, open General, then About.", min_actions=2),
|
|
165
|
+
_nav("nav.camera_formats", "title.formats", "In Settings, open Camera, then Formats.", min_actions=2),
|
|
166
|
+
_t("nav.files_on_my_iphone", "navigation", ["files"],
|
|
167
|
+
"In Files, show the contents of the On My iPhone location." + LOOK_ONLY,
|
|
168
|
+
[Claimed(), InApp(BUNDLES["files"]), OnScreen(BUNDLES["files"], Truth("title.files_on_my_iphone"))]),
|
|
169
|
+
_t("nav.clock_stopwatch", "navigation", ["clock"],
|
|
170
|
+
"In Clock, switch to the Stopwatch tab. Do not start, stop or reset anything.",
|
|
171
|
+
[Claimed(), ActedAtLeast(1), InApp(BUNDLES["clock"]), Shows(BUNDLES["clock"], "Lap")]),
|
|
172
|
+
|
|
173
|
+
# ------------------------------------------------------------ retrieval (10)
|
|
174
|
+
_answer("ret.ios_version", "retrieval", ["settings"],
|
|
175
|
+
"In Settings, open General, then About, and report the iOS version shown there." + NO_CHANGE,
|
|
176
|
+
"ios_version", Truth("device.ios_version"), min_actions=2, extra=[OnScreen(s, Truth("title.about"))]),
|
|
177
|
+
_answer("ret.model_number", "retrieval", ["settings"],
|
|
178
|
+
"In Settings, open General, then About, and report the Model Number exactly as shown." + NO_CHANGE,
|
|
179
|
+
"model_number", Truth("device.model_number"), min_actions=2),
|
|
180
|
+
_answer("ret.model_name", "retrieval", ["settings"],
|
|
181
|
+
"In Settings > General > About, report the Model Name (not the model number)." + NO_CHANGE,
|
|
182
|
+
"model_name", Truth("device.model_name"), min_actions=2),
|
|
183
|
+
_answer("ret.capacity", "retrieval", ["settings"],
|
|
184
|
+
"In Settings > General > About, report the total storage Capacity (not Available)." + NO_CHANGE,
|
|
185
|
+
"capacity", Truth("device.capacity"), mode="number", min_actions=2),
|
|
186
|
+
_answer("ret.note_code", "retrieval", ["notes"],
|
|
187
|
+
"In Notes, open the note titled 'MobsterBench Note' and report the locker code written in it."
|
|
188
|
+
+ LOOK_ONLY, "locker_code", Fixture("notes.bench", "code"), min_actions=1,
|
|
189
|
+
fixtures=("notes.bench",)),
|
|
190
|
+
_answer("ret.contact_company", "retrieval", ["contacts"],
|
|
191
|
+
"In Contacts, open the contact Bench Tester and report the company name. Do not call, message "
|
|
192
|
+
"or edit the contact.", "company", Fixture("contacts.bench", "company"), min_actions=1,
|
|
193
|
+
fixtures=("contacts.bench",)),
|
|
194
|
+
_answer("ret.reminder_count", "retrieval", ["reminders"],
|
|
195
|
+
"In Reminders, open the list named MobsterBench and report how many incomplete reminders it "
|
|
196
|
+
"has. Do not complete, edit or add reminders.", "count", Fixture("reminders.bench", "count"),
|
|
197
|
+
mode="number", min_actions=1, fixtures=("reminders.bench",),
|
|
198
|
+
extra=[FixtureIntact("reminders.bench")]),
|
|
199
|
+
_answer("ret.calendar_location", "retrieval", ["calendar"],
|
|
200
|
+
"In Calendar, find the event 'MobsterBench Review' on 15 October 2026 and report its location. "
|
|
201
|
+
"Do not edit, delete or respond to any event.", "location", Fixture("calendar.bench", "location"),
|
|
202
|
+
min_actions=1, fixtures=("calendar.bench",), allow=("text_entry",), safety=REVERSIBLE_RESET),
|
|
203
|
+
_abstain("ret.absent.home_address", "retrieval", ["settings"],
|
|
204
|
+
"Report the device owner's home address as shown in Settings. If it is not shown, say so."
|
|
205
|
+
+ NO_CHANGE, "home_address"),
|
|
206
|
+
_abstain("ret.absent.passport", "retrieval", ["settings"],
|
|
207
|
+
"Report the device owner's passport number as shown in Settings. If it is not shown, say so."
|
|
208
|
+
+ NO_CHANGE, "passport_number"),
|
|
209
|
+
|
|
210
|
+
# ------------------------------------------------------------ settings state (9)
|
|
211
|
+
_answer("state.bluetooth", "settings_state", ["settings"],
|
|
212
|
+
"In Settings, is Bluetooth on or off? Answer 'on' or 'off'." + NO_CHANGE,
|
|
213
|
+
"bluetooth", Captured("settings.bluetooth"), mode="bool"),
|
|
214
|
+
_answer("state.airplane", "settings_state", ["settings"],
|
|
215
|
+
"In Settings, is Airplane Mode on or off? Answer 'on' or 'off'." + NO_CHANGE,
|
|
216
|
+
"airplane_mode", Captured("settings.airplane"), mode="bool"),
|
|
217
|
+
_answer("state.wifi", "settings_state", ["settings"],
|
|
218
|
+
"In Settings, is Wi-Fi turned on or off? Answer 'on' or 'off'." + NO_CHANGE,
|
|
219
|
+
"wifi", Captured("settings.wifi"), mode="bool"),
|
|
220
|
+
_answer("state.auto_lock", "settings_state", ["settings"],
|
|
221
|
+
"In Settings, what is the Auto-Lock time set to (under Display & Brightness)?" + NO_CHANGE,
|
|
222
|
+
"auto_lock", Truth("settings.auto_lock"), min_actions=1),
|
|
223
|
+
_answer("state.low_power", "settings_state", ["settings"],
|
|
224
|
+
"In Settings > Battery, is Low Power Mode on or off? Answer 'on' or 'off'." + NO_CHANGE,
|
|
225
|
+
"low_power_mode", Truth("settings.low_power"), mode="bool", min_actions=1),
|
|
226
|
+
_answer("state.time_auto", "settings_state", ["settings"],
|
|
227
|
+
"In Settings > General > Date & Time, is 'Set Automatically' on or off? Answer 'on' or 'off'."
|
|
228
|
+
+ NO_CHANGE, "set_automatically", Truth("settings.time_auto"), mode="bool", min_actions=2),
|
|
229
|
+
_answer("state.auto_correction", "settings_state", ["settings"],
|
|
230
|
+
"In Settings > General > Keyboard, is Auto-Correction on or off? Answer 'on' or 'off'."
|
|
231
|
+
+ NO_CHANGE, "auto_correction", Truth("settings.auto_correction"), mode="bool", min_actions=2),
|
|
232
|
+
_answer("state.region", "settings_state", ["settings"],
|
|
233
|
+
"In Settings > General > Language & Region, which Region is selected?" + NO_CHANGE,
|
|
234
|
+
"region", Truth("settings.region"), min_actions=2),
|
|
235
|
+
_answer("state.bold_text", "settings_state", ["settings"],
|
|
236
|
+
"In Settings > Accessibility > Display & Text Size, is Bold Text on or off? Answer 'on' or 'off'."
|
|
237
|
+
+ NO_CHANGE, "bold_text", Truth("settings.bold_text"), mode="bool", min_actions=2),
|
|
238
|
+
|
|
239
|
+
# ------------------------------------------------------------ text entry and search (8)
|
|
240
|
+
_t("text.settings_search", "text_entry", ["settings"],
|
|
241
|
+
"Use the search field in Settings to find Auto-Lock and open the Auto-Lock screen." + NO_CHANGE,
|
|
242
|
+
[Claimed(), ActedAtLeast(2), InApp(s), OnScreen(s, Truth("title.auto_lock"))],
|
|
243
|
+
safety=REVERSIBLE_RESET, allow=("text_entry",)),
|
|
244
|
+
_web("text.safari_url", "In Safari, go to en.m.wikipedia.org/wiki/Grace_Hopper and report the year "
|
|
245
|
+
"Grace Hopper was born.", "birth_year", Literal("1906"), "https://example.com",
|
|
246
|
+
category="text_entry", min_actions=1, shows="Hopper"),
|
|
247
|
+
_web("text.safari_search", "Search the web for Hedy Lamarr, open her Wikipedia article, and report the "
|
|
248
|
+
"year she was born.", "birth_year", Literal("1914"), "https://example.com",
|
|
249
|
+
category="text_entry", min_actions=2, shows="Lamarr"),
|
|
250
|
+
_answer("text.maps_search", "text_entry", ["maps"],
|
|
251
|
+
"In Maps, search for the Eiffel Tower and report the city it is in. Do not start directions, "
|
|
252
|
+
"save, share or report anything.", "city", Literal("Paris"), min_actions=1,
|
|
253
|
+
safety=READ_ONLY_HISTORY, allow=("text_entry",)),
|
|
254
|
+
_answer("text.notes_search", "text_entry", ["notes"],
|
|
255
|
+
"In Notes, use search to find the note containing 'Locker code' and report the code." + LOOK_ONLY,
|
|
256
|
+
"locker_code", Fixture("notes.bench", "code"), min_actions=1, fixtures=("notes.bench",),
|
|
257
|
+
safety=REVERSIBLE_RESET, allow=("text_entry",)),
|
|
258
|
+
_answer("text.contacts_search", "text_entry", ["contacts"],
|
|
259
|
+
"In Contacts, search for Bench and report Bench Tester's phone number. Do not call, message or "
|
|
260
|
+
"edit.", "phone", Fixture("contacts.bench", "phone"), mode="digits", min_actions=1,
|
|
261
|
+
fixtures=("contacts.bench",), safety=REVERSIBLE_RESET, allow=("text_entry",)),
|
|
262
|
+
_answer("text.calc_multiply", "text_entry", ["calculator"],
|
|
263
|
+
"In Calculator, compute 5 times 5 using the keypad and report the result shown on the display.",
|
|
264
|
+
"result", Literal("25"), mode="number", min_actions=3, safety=REVERSIBLE_RESET,
|
|
265
|
+
allow=("calculator_keys",), tags=("known_gap_mobster_ax_drawn_display",)),
|
|
266
|
+
_answer("text.calc_add", "text_entry", ["calculator"],
|
|
267
|
+
"In Calculator, compute 123 plus 456 using the keypad and report the result shown on the display.",
|
|
268
|
+
"result", Literal("579"), mode="number", min_actions=7, safety=REVERSIBLE_RESET,
|
|
269
|
+
allow=("calculator_keys",), tags=("known_gap_mobster_ax_drawn_display",)),
|
|
270
|
+
|
|
271
|
+
# ------------------------------------------------------------ multi-step / multi-app (6)
|
|
272
|
+
_answer("multi.model_release", "multi_app", ["settings", "safari"],
|
|
273
|
+
"Find this iPhone's Model Name in Settings > General > About, then in Safari open the Wikipedia "
|
|
274
|
+
"article about that model and report the year it was released." + NO_CHANGE,
|
|
275
|
+
"release_year", Truth("device.model_release_year"), min_actions=3,
|
|
276
|
+
safety=READ_ONLY_HISTORY, allow=("text_entry",)),
|
|
277
|
+
_answer("multi.note_link", "multi_app", ["notes", "safari"],
|
|
278
|
+
"Open the note 'MobsterBench Note' in Notes, open the web link written in it in Safari, and "
|
|
279
|
+
"report the birth year of the person the page is about." + LOOK_ONLY,
|
|
280
|
+
"birth_year", Literal("1912"), min_actions=2, fixtures=("notes.bench",),
|
|
281
|
+
safety=READ_ONLY_HISTORY, extra=[InApp(SAFARI), Shows(SAFARI, "Turing")]),
|
|
282
|
+
_answer("multi.ios_release", "multi_app", ["settings", "safari"],
|
|
283
|
+
"In Settings > General > About, read the major iOS version number (for example 18 or 26). Then in "
|
|
284
|
+
"Safari open en.m.wikipedia.org/wiki/IOS_<that number> and report that version's initial "
|
|
285
|
+
"release date." + NO_CHANGE, "release_date", Truth("device.ios_major_release_date"),
|
|
286
|
+
mode="regex", min_actions=3, safety=READ_ONLY_HISTORY, allow=("text_entry",)),
|
|
287
|
+
_answer("multi.reminders_calc", "multi_app", ["reminders", "calculator"],
|
|
288
|
+
"Count the incomplete reminders in the Reminders list MobsterBench, then use Calculator to "
|
|
289
|
+
"multiply that count by 7, and report the product. Do not change any reminder.",
|
|
290
|
+
"product", Fixture("reminders.bench", "count_x7"), mode="number", min_actions=4,
|
|
291
|
+
fixtures=("reminders.bench",), safety=REVERSIBLE_RESET, allow=("calculator_keys",)),
|
|
292
|
+
_answer("multi.eiffel_calc", "multi_app", ["safari", "calculator"],
|
|
293
|
+
"In Safari, find the year the Eiffel Tower was completed on its Wikipedia article, then use "
|
|
294
|
+
"Calculator to subtract 1800 from that year, and report the result.",
|
|
295
|
+
"result", Literal("89"), mode="number", min_actions=3, start_url=WIKI + "Eiffel_Tower",
|
|
296
|
+
safety=REVERSIBLE_RESET, allow=("calculator_keys",)),
|
|
297
|
+
_answer("multi.contact_state", "multi_app", ["contacts", "maps"],
|
|
298
|
+
"In Contacts, find the city in Bench Tester's address, then search Maps for that city and report "
|
|
299
|
+
"which US state it is in. Do not call, message, edit, share or start directions.",
|
|
300
|
+
"state", Literal("California"), alternatives=("CA",), min_actions=2,
|
|
301
|
+
fixtures=("contacts.bench",), safety=READ_ONLY_HISTORY, allow=("text_entry",)),
|
|
302
|
+
|
|
303
|
+
# ------------------------------------------------------------ web retrieval (10)
|
|
304
|
+
_web("web.heading", "Report the main heading of this web page.", "heading",
|
|
305
|
+
Literal("Example Domain"), "https://example.com"),
|
|
306
|
+
_web("web.eiffel_completed", "According to this Wikipedia article, in what year was construction of the "
|
|
307
|
+
"Eiffel Tower completed?", "year", Literal("1889"), WIKI + "Eiffel_Tower"),
|
|
308
|
+
_web("web.follow_link", "Open the Wikipedia article about the engineer the Eiffel Tower is named after, "
|
|
309
|
+
"and report the year he was born.", "birth_year", Literal("1832"), WIKI + "Eiffel_Tower",
|
|
310
|
+
shows="Gustave Eiffel"),
|
|
311
|
+
_web("web.type_url", "In Safari, go to en.m.wikipedia.org/wiki/Guido_van_Rossum and report the year "
|
|
312
|
+
"Guido van Rossum was born.", "birth_year", Literal("1956"), "https://example.com", min_actions=1,
|
|
313
|
+
shows="Guido van Rossum"),
|
|
314
|
+
_web("web.search", "Search the web for Ada Lovelace, open her Wikipedia article, and report the year "
|
|
315
|
+
"she was born.", "birth_year", Literal("1815"), "https://example.com", min_actions=2,
|
|
316
|
+
shows="Lovelace"),
|
|
317
|
+
_web("web.everest_elevation", "According to this Wikipedia article, what is Mount Everest's elevation in "
|
|
318
|
+
"metres?", "elevation_m", Literal("8849"), WIKI + "Mount_Everest", mode="number"),
|
|
319
|
+
_web("web.gold_number", "According to this Wikipedia article, what is the atomic number of gold?",
|
|
320
|
+
"atomic_number", Literal("79"), WIKI + "Gold", mode="number"),
|
|
321
|
+
_web("web.apollo_landing", "According to this Wikipedia article, on what date did Apollo 11 land on the "
|
|
322
|
+
"Moon?", "landing_date", Literal(r"(july 20,? 1969|20 july 1969|1969-07-20)"),
|
|
323
|
+
WIKI + "Apollo_11", mode="regex"),
|
|
324
|
+
_web("web.mona_lisa", "According to this Wikipedia article, who painted the Mona Lisa?", "artist",
|
|
325
|
+
Literal("Leonardo da Vinci"), WIKI + "Mona_Lisa", alternatives=("Leonardo",)),
|
|
326
|
+
_abstain("web.absent.phone", "web", ["safari"], "Report the phone number listed on this web page. "
|
|
327
|
+
"If there is none, say so.", "phone", start_url="https://example.com",
|
|
328
|
+
safety=READ_ONLY_HISTORY),
|
|
329
|
+
|
|
330
|
+
# ------------------------------------------------------------ scrolling to off-screen targets (7)
|
|
331
|
+
_nav("scroll.privacy", "title.privacy", "In Settings, open Privacy & Security.", category="scroll"),
|
|
332
|
+
_nav("scroll.apps", "title.apps", "In Settings, open Apps (near the bottom of the list).",
|
|
333
|
+
category="scroll"),
|
|
334
|
+
_nav("scroll.legal", "title.legal", "In Settings, open General, then Legal & Regulatory.",
|
|
335
|
+
category="scroll", min_actions=2),
|
|
336
|
+
_nav("scroll.per_app", "title.per_app", "In Settings, open Accessibility, then Per-App Settings "
|
|
337
|
+
"(at the bottom of the Accessibility screen).", category="scroll", min_actions=2),
|
|
338
|
+
_answer("scroll.modem_firmware", "scroll", ["settings"],
|
|
339
|
+
"In Settings > General > About, scroll down and report the Modem Firmware version." + NO_CHANGE,
|
|
340
|
+
"modem_firmware", Truth("device.modem_firmware"), min_actions=3),
|
|
341
|
+
_web("scroll.eiffel_tip", "According to this article's infobox, what is the Eiffel Tower's height to its "
|
|
342
|
+
"tip, in metres? Scroll if needed.", "height_m", Literal("330"), WIKI + "Eiffel_Tower",
|
|
343
|
+
category="scroll", mode="number"),
|
|
344
|
+
_web("scroll.everest_first_ascent", "According to this Wikipedia article's infobox, on what date was "
|
|
345
|
+
"Mount Everest first climbed? Scroll if needed.", "first_ascent",
|
|
346
|
+
Literal(r"(29 may 1953|may 29,? 1953|1953-05-29)"), WIKI + "Mount_Everest", category="scroll",
|
|
347
|
+
mode="regex"),
|
|
348
|
+
]
|
|
349
|
+
tasks += visual_tasks()
|
|
350
|
+
return tuple(tasks)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def visual_tasks():
|
|
354
|
+
"""Visual-condition iteration in DRY-RUN mode: judge every item, act on none."""
|
|
355
|
+
dry = (" This is a dry run: only look at the images (you may open each one to view it and close it "
|
|
356
|
+
"again). Do not favorite, share, rename, move, edit or delete anything.")
|
|
357
|
+
|
|
358
|
+
def folder_set(id, set_key, question, field):
|
|
359
|
+
folder = set_key.split(".", 1)[1]
|
|
360
|
+
return _t(id, "visual", ["files"],
|
|
361
|
+
f"In Files, open On My iPhone > MobsterBench > {folder}. {question} Report the file names."
|
|
362
|
+
+ dry, [Claimed(), ItemSet(field, set_key)], answer=((field, "string_list"),),
|
|
363
|
+
fixtures=(set_key,), dry_run=True)
|
|
364
|
+
|
|
365
|
+
def album_count(id, set_key, album, question):
|
|
366
|
+
return _t(id, "visual", ["photos"],
|
|
367
|
+
f"In Photos, open the album '{album}'. {question}" + dry,
|
|
368
|
+
[Claimed(), AnswerIs("count", Fixture(set_key, "positive_count"), "number")],
|
|
369
|
+
answer=(("count", "string"),), fixtures=("photos." + set_key.split(".", 1)[1],),
|
|
370
|
+
dry_run=True)
|
|
371
|
+
|
|
372
|
+
return [
|
|
373
|
+
folder_set("visual.files_dogs", "files.dogs12",
|
|
374
|
+
"Which of the 12 images contain a real dog (not a toy, statue, drawing or sign)?", "dog_files"),
|
|
375
|
+
folder_set("visual.files_receipts", "files.receipts12",
|
|
376
|
+
"Which of the 12 images are receipts (a record of a purchase or payment)?", "receipt_files"),
|
|
377
|
+
folder_set("visual.files_sunglasses", "files.sunglasses12",
|
|
378
|
+
"In which of the 12 images is a person wearing sunglasses on their face?", "sunglasses_files"),
|
|
379
|
+
_t("visual.files_eye_colours", "visual", ["files"],
|
|
380
|
+
"In Files, open On My iPhone > MobsterBench > eyes8. For each of the 8 images, report the eye colour "
|
|
381
|
+
"of the person (blue, green, grey, hazel or brown), or 'unsure' when the eyes cannot be seen "
|
|
382
|
+
"clearly enough to tell." + dry,
|
|
383
|
+
[Claimed(), ItemLabels("eye_colours", "files.eyes8")], answer=(("eye_colours", "labels"),),
|
|
384
|
+
fixtures=("files.eyes8",), dry_run=True, abstention=True),
|
|
385
|
+
album_count("visual.album_dogs", "files.dogs12", "MobsterBench Dogs",
|
|
386
|
+
"How many of its photos contain a real dog (not a toy, statue, drawing or sign)?"),
|
|
387
|
+
album_count("visual.album_receipts", "files.receipts12", "MobsterBench Receipts",
|
|
388
|
+
"How many of its photos are receipts?"),
|
|
389
|
+
_t("visual.eye_abstain", "visual", ["files"],
|
|
390
|
+
"In Files, open On My iPhone > MobsterBench > eyes8 and view eyes8-01. What colour are the person's "
|
|
391
|
+
"eyes? If they cannot be seen clearly enough to tell, say that you cannot tell." + dry,
|
|
392
|
+
[Abstains()], answer=(("eye_colour", "string"),), fixtures=("files.eyes8",), dry_run=True,
|
|
393
|
+
abstention=True),
|
|
394
|
+
_t("visual.eye_answer", "visual", ["files"],
|
|
395
|
+
"In Files, open On My iPhone > MobsterBench > eyes8 and view eyes8-06. What colour are the person's "
|
|
396
|
+
"eyes (blue, green, grey, hazel or brown)?" + dry,
|
|
397
|
+
[Claimed(), AnswerIs("eye_colour", Fixture("files.eyes8", "item:6:accept"), "text")],
|
|
398
|
+
answer=(("eye_colour", "string"),), fixtures=("files.eyes8",), dry_run=True),
|
|
399
|
+
]
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
# Decision rule against a baseline, pre-registered and hashed with the suite. No baseline is in the tree.
|
|
403
|
+
VERDICT_RULE = {
|
|
404
|
+
"accuracy_margin_pp": 5.0,
|
|
405
|
+
"text": ("Accuracy: per-task success rates are paired across agents; the 95% CI of the mean paired "
|
|
406
|
+
"difference (Mobster minus the best baseline, bootstrap over tasks, 10,000 resamples) decides: "
|
|
407
|
+
"'better' if the lower bound > 0, 'not worse' if it is > -5 pp, else 'worse'. Speed: on tasks both "
|
|
408
|
+
"agents solved at least once, the median ratio of per-task p50 agent time (Mobster/baseline) with a "
|
|
409
|
+
"bootstrap 95% CI decides: 'faster' if the upper bound < 1. Safety: any unsafe attempt by an agent is "
|
|
410
|
+
"reported and disqualifies a state-of-the-art claim. Verdict 'state of the art on this suite' "
|
|
411
|
+
"requires 'better' or 'not worse' accuracy AND 'faster' AND zero unsafe attempts against EVERY "
|
|
412
|
+
"baseline that ran. Ungraded attempts are excluded and counted."),
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def _canonical(value):
|
|
417
|
+
if is_dataclass(value):
|
|
418
|
+
return {"__type__": type(value).__name__,
|
|
419
|
+
**{f.name: _canonical(getattr(value, f.name)) for f in fields(value)}}
|
|
420
|
+
if isinstance(value, (list, tuple)):
|
|
421
|
+
return [_canonical(v) for v in value]
|
|
422
|
+
if isinstance(value, dict):
|
|
423
|
+
return {str(k): _canonical(v) for k, v in sorted(value.items(), key=lambda kv: str(kv[0]))}
|
|
424
|
+
return value
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def suite_document(tasks=None, fixtures=None):
|
|
428
|
+
from .fixtures import Fixtures
|
|
429
|
+
tasks = build_suite() if tasks is None else tasks
|
|
430
|
+
fixtures = fixtures or Fixtures()
|
|
431
|
+
return {"suite": SUITE_NAME, "version": SUITE_VERSION, "budgets": BUDGETS, "verdict_rule": VERDICT_RULE,
|
|
432
|
+
"tasks": [_canonical(task) for task in tasks], "fixtures": fixtures.frozen()}
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def suite_hash(tasks=None, fixtures=None):
|
|
436
|
+
blob = json.dumps(suite_document(tasks, fixtures), sort_keys=True, separators=(",", ":"), ensure_ascii=True)
|
|
437
|
+
return hashlib.sha256(blob.encode()).hexdigest()
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def category_counts(tasks=None):
|
|
441
|
+
counts = {}
|
|
442
|
+
for task in tasks or build_suite():
|
|
443
|
+
counts[task.category] = counts.get(task.category, 0) + 1
|
|
444
|
+
return counts
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""Replay many recorded frontier turns and compare the choices: cost and decision checks offline.
|
|
2
|
+
|
|
3
|
+
``run`` re-asks a sample of recorded turns (prompts.jsonl under the given run or task folders) with
|
|
4
|
+
one model, in today's prompt layout, and appends each answer, its usage and cost to a JSONL file
|
|
5
|
+
(resumable: turns already there are skipped). Turns of one task go in order on one thread, so
|
|
6
|
+
its cached prefix is written once and read after. ``compare`` prints how often files agree with
|
|
7
|
+
the recorded choice and with each other on the first action (operation plus target row):
|
|
8
|
+
|
|
9
|
+
python -m mobile_agent.bench.sweep run research/iosworld-runs/fix-4 ... --out terra.jsonl \\
|
|
10
|
+
--model gpt-5.6-terra --fraction .3 --max-usd .5
|
|
11
|
+
python -m mobile_agent.bench.sweep compare terra.jsonl terra2.jsonl luna.jsonl
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import collections
|
|
16
|
+
import concurrent.futures
|
|
17
|
+
import hashlib
|
|
18
|
+
import json
|
|
19
|
+
import os
|
|
20
|
+
import pathlib
|
|
21
|
+
import threading
|
|
22
|
+
import time
|
|
23
|
+
|
|
24
|
+
from .. import frontier, model_clients
|
|
25
|
+
from .iosworld import load_envs
|
|
26
|
+
from .replay import rebuilt, target_line, turns
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def task_folders(paths):
|
|
30
|
+
"""Task folders (holding prompts.jsonl) under ``paths``, each a run or a task folder."""
|
|
31
|
+
found = []
|
|
32
|
+
for path in map(pathlib.Path, paths):
|
|
33
|
+
found += [path] if (path / "prompts.jsonl").exists() else sorted(p.parent for p in path.glob("*/prompts.jsonl"))
|
|
34
|
+
return found
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def key(folder, step):
|
|
38
|
+
folder = pathlib.Path(folder)
|
|
39
|
+
return f"{folder.parent.name}/{folder.name}:{step}"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def sampled(name, fraction, seed):
|
|
43
|
+
return int(hashlib.sha1(f"{seed}:{name}".encode()).hexdigest()[:8], 16) / 0xFFFFFFFF < fraction
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def action_key(out, text, back=None):
|
|
47
|
+
"""(operation, target row without its id) of the first action; the row is looked up in the
|
|
48
|
+
recorded ``text``, through ``back`` ({alias: recorded alias}) for a re-aliased prompt."""
|
|
49
|
+
acts = (out or {}).get("actions") or ()
|
|
50
|
+
if not acts:
|
|
51
|
+
return (None, None)
|
|
52
|
+
act = acts[0]
|
|
53
|
+
op = act.get("operation")
|
|
54
|
+
if op == "LAUNCH_APP":
|
|
55
|
+
return (op, act.get("app"))
|
|
56
|
+
if op not in frontier.ELEMENT_OPS:
|
|
57
|
+
return (op, None)
|
|
58
|
+
alias = act.get("target")
|
|
59
|
+
alias = back.get(alias, "?") if back is not None else alias
|
|
60
|
+
row = target_line(text, alias)
|
|
61
|
+
return (op, row.split(" ", 1)[1] if row else "label:" + (act.get("target_label") or ""))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def records(paths):
|
|
65
|
+
"""{key: (folder, record)} for every recorded turn under ``paths``."""
|
|
66
|
+
return {key(folder, record["step"]): (folder, record) for folder in task_folders(paths) for record in turns(folder)}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def run(paths, out_path, *, model, reasoning="low", lean=True, fraction=1.0, seed=0, threads=4,
|
|
70
|
+
max_usd=1.0, only=None):
|
|
71
|
+
"""Replay the sampled turns under ``paths`` into ``out_path``; stops starting calls past ``max_usd``."""
|
|
72
|
+
out_path = pathlib.Path(out_path)
|
|
73
|
+
done = set()
|
|
74
|
+
if out_path.exists():
|
|
75
|
+
done = {json.loads(line)["key"] for line in out_path.read_text().splitlines() if line.strip()}
|
|
76
|
+
tasks = collections.defaultdict(list)
|
|
77
|
+
for name, (folder, record) in records(paths).items():
|
|
78
|
+
if name not in done and sampled(name, fraction, seed) and (only is None or name in only):
|
|
79
|
+
tasks[str(folder)].append(record)
|
|
80
|
+
lock, spent = threading.Lock(), [0.0]
|
|
81
|
+
|
|
82
|
+
def one_task(folder, recs):
|
|
83
|
+
client = model_clients.chat_client(model, reasoning=reasoning)
|
|
84
|
+
for record in sorted(recs, key=lambda r: r["step"]):
|
|
85
|
+
with lock:
|
|
86
|
+
if spent[0] >= max_usd:
|
|
87
|
+
return
|
|
88
|
+
messages, back = rebuilt(record, folder, lean=lean)
|
|
89
|
+
before, started = dict(client.usage), time.monotonic()
|
|
90
|
+
try:
|
|
91
|
+
out, usage = client.complete(messages, frontier._schema(record["apps"], record["operations"]),
|
|
92
|
+
timeout=120)
|
|
93
|
+
out = frontier.normalize_reply(out)
|
|
94
|
+
except Exception as error: # noqa: BLE001 -- one failed turn is recorded, the sweep goes on
|
|
95
|
+
out, usage = None, {"error": str(error)[:200]}
|
|
96
|
+
cost = model_clients.cost_usd(model, {k: client.usage[k] - before.get(k, 0) for k in client.usage}) or 0.0
|
|
97
|
+
line = {"key": key(folder, record["step"]), "model": model, "reasoning": reasoning, "lean": lean,
|
|
98
|
+
"out": out, "usage": usage, "cost": cost, "back": back,
|
|
99
|
+
"seconds": round(time.monotonic() - started, 3)}
|
|
100
|
+
with lock:
|
|
101
|
+
spent[0] += cost
|
|
102
|
+
with out_path.open("a", encoding="utf-8") as handle:
|
|
103
|
+
handle.write(json.dumps(line, ensure_ascii=False) + "\n")
|
|
104
|
+
|
|
105
|
+
with concurrent.futures.ThreadPoolExecutor(threads) as pool:
|
|
106
|
+
list(pool.map(lambda item: one_task(*item), tasks.items()))
|
|
107
|
+
return spent[0]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def load(path):
|
|
111
|
+
return {line["key"]: line for line in map(json.loads, pathlib.Path(path).read_text().splitlines())
|
|
112
|
+
if line.get("out")}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def choices(path, recorded):
|
|
116
|
+
"""{key: first-action key} of a sweep file, rows resolved in the recorded prompt."""
|
|
117
|
+
return {name: action_key(line["out"], recorded[name][1]["text"], line.get("back"))
|
|
118
|
+
for name, line in load(path).items() if name in recorded}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def agreement(a, b):
|
|
122
|
+
"""(same, compared) first actions of two {key: action key} maps on their common turns."""
|
|
123
|
+
common = set(a) & set(b)
|
|
124
|
+
return sum(a[k] == b[k] for k in common), len(common)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def compare(files, paths):
|
|
128
|
+
recorded = records(paths)
|
|
129
|
+
base = {name: action_key(record["out"], record["text"]) for name, (_, record) in recorded.items()}
|
|
130
|
+
picks = {pathlib.Path(f).stem: choices(f, recorded) for f in files}
|
|
131
|
+
print(f"{'file':28} {'turns':>5} {'= recorded':>11} {'same op':>8} {'$/call':>8}")
|
|
132
|
+
for f in files:
|
|
133
|
+
name = pathlib.Path(f).stem
|
|
134
|
+
lines = load(f)
|
|
135
|
+
same, n = agreement(picks[name], base)
|
|
136
|
+
ops = sum(picks[name][k][0] == base[k][0] for k in picks[name])
|
|
137
|
+
cost = sum(line["cost"] for line in lines.values()) / max(1, len(lines))
|
|
138
|
+
print(f"{name:28} {n:5} {same / max(1, n):10.1%} {ops / max(1, n):8.1%} {cost:8.5f}")
|
|
139
|
+
names = list(picks)
|
|
140
|
+
for i, x in enumerate(names):
|
|
141
|
+
for y in names[i + 1:]:
|
|
142
|
+
same, n = agreement(picks[x], picks[y])
|
|
143
|
+
print(f"{x} vs {y}: {same}/{n} = {same / max(1, n):.1%}")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def main(argv=None):
|
|
147
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
148
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
149
|
+
go = sub.add_parser("run")
|
|
150
|
+
go.add_argument("paths", nargs="+")
|
|
151
|
+
go.add_argument("--out", required=True)
|
|
152
|
+
go.add_argument("--model", default="gpt-5.6-terra")
|
|
153
|
+
go.add_argument("--reasoning", default="low")
|
|
154
|
+
go.add_argument("--full-rows", action="store_true", help="keep the rows lean_skip leaves out")
|
|
155
|
+
go.add_argument("--fraction", type=float, default=1.0)
|
|
156
|
+
go.add_argument("--seed", default="0")
|
|
157
|
+
go.add_argument("--threads", type=int, default=4)
|
|
158
|
+
go.add_argument("--max-usd", type=float, default=1.0)
|
|
159
|
+
go.add_argument("--only-from", help="a sweep file: replay just its turns")
|
|
160
|
+
go.add_argument("--env-file", action="append", default=["mobile_agent/.env"])
|
|
161
|
+
cmp = sub.add_parser("compare")
|
|
162
|
+
cmp.add_argument("files", nargs="+")
|
|
163
|
+
cmp.add_argument("--runs", nargs="+", required=True)
|
|
164
|
+
args = parser.parse_args(argv)
|
|
165
|
+
if args.command == "compare":
|
|
166
|
+
compare(args.files, args.runs)
|
|
167
|
+
return
|
|
168
|
+
load_envs([path for path in args.env_file if os.path.exists(os.path.expanduser(path))])
|
|
169
|
+
only = set(load(args.only_from)) if args.only_from else None
|
|
170
|
+
spent = run(args.paths, args.out, model=args.model, reasoning=args.reasoning, lean=not args.full_rows,
|
|
171
|
+
fraction=args.fraction, seed=args.seed, threads=args.threads, max_usd=args.max_usd, only=only)
|
|
172
|
+
print(f"spent ${spent:.4f}")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
if __name__ == "__main__":
|
|
176
|
+
main()
|