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,490 @@
|
|
|
1
|
+
"""The result of a Smart run: its status, outcome, reason and the answer put into the user's structure (``summarize``).
|
|
2
|
+
Nothing here changes a decision the loop makes."""
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from . import harness_api
|
|
8
|
+
from .agent_hooks import STOP_CODES
|
|
9
|
+
from .engines import (
|
|
10
|
+
ANTHROPIC_CREDIT,
|
|
11
|
+
CREDIT_CODES,
|
|
12
|
+
PROVIDER_ERROR,
|
|
13
|
+
SMART,
|
|
14
|
+
SMART_CONFIG,
|
|
15
|
+
account_name,
|
|
16
|
+
credit_provider,
|
|
17
|
+
model_error,
|
|
18
|
+
out_of_credit,
|
|
19
|
+
plain_error,
|
|
20
|
+
smart_model,
|
|
21
|
+
)
|
|
22
|
+
from .smart_events import item_text
|
|
23
|
+
|
|
24
|
+
STATUS = {"completed": "completed", "blocked": "blocked", "max_steps": "max_steps", "timeout": "timeout",
|
|
25
|
+
"budget": "spend_cap", "error": "error", "approval_denied": "approval_denied",
|
|
26
|
+
"approval_timeout": "approval_timeout", "stopped": "stopped"}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Past-tense verbs "I" can go before: "I found 3 reminders" reads as "Found 3 reminders", like the steps.
|
|
30
|
+
# Anything else keeps it: "I have added…", "I don't see…" or "I see…" would read as a broken sentence or
|
|
31
|
+
# an instruction without it, and "I 95 is closed" or "I miss you" are the phone's own words.
|
|
32
|
+
DROPS_SUBJECT = frozenset({"found", "sent", "made", "set", "put", "wrote", "took", "got", "saw", "ran", "read",
|
|
33
|
+
"left", "opened", "closed", "couldn't"})
|
|
34
|
+
NOT_PAST = frozenset({"need", "feed", "bleed", "breed", "speed", "exceed", "proceed", "succeed", "heed", "seed",
|
|
35
|
+
"weed", "bed", "wed", "red", "shed", "embed"})
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def without_first_person(answer):
|
|
39
|
+
found = re.match(r"I ([A-Za-z]+(?:['’][A-Za-z]+)?)\b", answer or "")
|
|
40
|
+
if not found:
|
|
41
|
+
return answer
|
|
42
|
+
verb = found.group(1).casefold().replace("’", "'")
|
|
43
|
+
if verb not in DROPS_SUBJECT and not (verb.endswith("ed") and verb not in NOT_PAST):
|
|
44
|
+
return answer
|
|
45
|
+
return answer[2].upper() + answer[3:]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def tells_what_it_did(sentence, contract, proof=()):
|
|
49
|
+
from . import contract_screen as KS
|
|
50
|
+
if contract is None or not any(item.kind in ("COMMIT", "WRITE") for item in contract.items):
|
|
51
|
+
return False
|
|
52
|
+
said = KS.plain(sentence).rstrip(".!?…")
|
|
53
|
+
return not any(said and said in KS.plain(entry.get("quote")) for entry in proof or ())
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
SENTENCE_END = re.compile(r"[.!?](?=\s|$)")
|
|
57
|
+
LIST_NUMBER = re.compile(r"(?:^|\n[ \t]*|[:;][ \t]+)\d{1,2}\.$")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def sentence_end(text):
|
|
61
|
+
"""Where the first sentence of ``text`` ends (just past its mark), or None."""
|
|
62
|
+
for mark in SENTENCE_END.finditer(text):
|
|
63
|
+
if not LIST_NUMBER.search(text[:mark.end()]):
|
|
64
|
+
return mark.end()
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
_MARKS = ((re.compile(r"^(?:#{1,6}\s+|>\s*)"), ""),
|
|
69
|
+
(re.compile(r"!?\[([^\]\n]*)\]\([^)\s]*\)"), r"\1"),
|
|
70
|
+
(re.compile(r"(\*\*|__)(?=\S)(.+?)(?<=\S)\1"), r"\2"),
|
|
71
|
+
(re.compile(r"(?<![\w*])\*(?=\S)([^*\n]+?)(?<=\S)\*(?![\w*])"), r"\1"),
|
|
72
|
+
(re.compile(r"`([^`\n]+)`"), r"\1"))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def plain_marks(text):
|
|
76
|
+
for pattern, replacement in _MARKS:
|
|
77
|
+
text = pattern.sub(replacement, text)
|
|
78
|
+
return text.strip()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def first_sentence(text, limit=300):
|
|
82
|
+
text = str(text or "").strip()
|
|
83
|
+
if not text:
|
|
84
|
+
return None
|
|
85
|
+
line, end = text.find("\n"), sentence_end(text)
|
|
86
|
+
if line != -1 and (end is None or end > line):
|
|
87
|
+
sentence = text[:line]
|
|
88
|
+
elif end is not None and len(" ".join(text[:end].split())) >= 12:
|
|
89
|
+
sentence = text[:end]
|
|
90
|
+
else:
|
|
91
|
+
sentence = text
|
|
92
|
+
sentence = plain_marks(" ".join(sentence.split()))
|
|
93
|
+
return sentence if len(sentence) <= limit else sentence[:limit - 1].rstrip() + "…"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _answer_values(data):
|
|
97
|
+
"""The scalar values of a structured answer, as plain text to look for (numbers without grouping commas)."""
|
|
98
|
+
values = []
|
|
99
|
+
for value in (data.values() if isinstance(data, dict) else ()):
|
|
100
|
+
if isinstance(value, (str, int, float)) and not isinstance(value, bool) and str(value).strip():
|
|
101
|
+
values.append(str(value).strip())
|
|
102
|
+
return values
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _mentions(sentence, value):
|
|
106
|
+
plain = " ".join(str(sentence or "").casefold().replace(",", "").split())
|
|
107
|
+
return " ".join(value.casefold().replace(",", "").split()) in plain
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def lead_sentence(full, data):
|
|
111
|
+
values = _answer_values(data)
|
|
112
|
+
if not values or not full:
|
|
113
|
+
return None
|
|
114
|
+
rest = str(full).strip()
|
|
115
|
+
first = first_sentence(rest)
|
|
116
|
+
if first and any(_mentions(first, value) for value in values):
|
|
117
|
+
return None
|
|
118
|
+
while rest:
|
|
119
|
+
end = sentence_end(rest)
|
|
120
|
+
sentence = " ".join((rest[:end] if end else rest).split())
|
|
121
|
+
if sentence and any(_mentions(sentence, value) for value in values):
|
|
122
|
+
return sentence if len(sentence) <= 300 else sentence[:299].rstrip() + "…"
|
|
123
|
+
rest = rest[end:].strip() if end else ""
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def outcome_of(status, contract, answer):
|
|
128
|
+
"""done | check | couldnt_finish | stopped | declined."""
|
|
129
|
+
if status == "approval_denied":
|
|
130
|
+
return "declined"
|
|
131
|
+
if status in ("stopped", "approval_timeout"):
|
|
132
|
+
return "stopped"
|
|
133
|
+
if status == "completed":
|
|
134
|
+
unproven = [i for i in (contract.unproven() if contract else ()) if i.kind in ("COMMIT", "WRITE", "REPORT")]
|
|
135
|
+
return "check" if unproven or contract is None else "done"
|
|
136
|
+
if status in ("max_steps", "timeout", "spend_cap", "blocked", "error") and answer and status != "error":
|
|
137
|
+
return "check" if status != "blocked" else "couldnt_finish"
|
|
138
|
+
return "couldnt_finish"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def reason_of(status, outcome, raw_reason, contract, model_failed=False, model=None):
|
|
142
|
+
if outcome == "done":
|
|
143
|
+
return None
|
|
144
|
+
if outcome == "check":
|
|
145
|
+
unproven = [i.what for i in (contract.unproven() if contract else ()) if i.kind in ("COMMIT", "WRITE")]
|
|
146
|
+
if unproven:
|
|
147
|
+
return "The screen never showed this finished: " + "; ".join(unproven[:3]) + "."
|
|
148
|
+
if status == "spend_cap":
|
|
149
|
+
return "The task reached its cost limit. This is what it found before stopping."
|
|
150
|
+
if status in ("max_steps", "timeout"):
|
|
151
|
+
return "The task ran out of steps. This is what it found before stopping."
|
|
152
|
+
return "Mobster couldn't prove every part of this on screen. Check the answer."
|
|
153
|
+
plain = plain_error(raw_reason, model_failed, model)
|
|
154
|
+
if plain:
|
|
155
|
+
return plain
|
|
156
|
+
if status == "spend_cap":
|
|
157
|
+
return "The task reached its cost limit before finishing."
|
|
158
|
+
if status == "max_steps":
|
|
159
|
+
actions = re.match(r"(\d+) actions used", str(raw_reason or ""))
|
|
160
|
+
if actions:
|
|
161
|
+
return f"The task took {actions.group(1)} actions, the most one task can take, before finishing."
|
|
162
|
+
return f"The task used all {SMART_CONFIG.max_steps} steps before finishing."
|
|
163
|
+
if status == "timeout":
|
|
164
|
+
return "The task ran out of time before finishing."
|
|
165
|
+
if status == "blocked":
|
|
166
|
+
return str(raw_reason or "Mobster couldn't do this on your iPhone.")[:300]
|
|
167
|
+
return str(raw_reason or "The task stopped before finishing.")[:300]
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _findings(request, answer, notes, instruction):
|
|
171
|
+
"""The messages of a call that puts the loop's findings (its answer and notes) into a structure."""
|
|
172
|
+
return [{"role": "system", "content": instruction + " Use only values stated in its answer or notes, exactly as "
|
|
173
|
+
"written there; use null where a value was not found."},
|
|
174
|
+
{"role": "user", "content": [{"type": "text", "text": f"Request: {request}\n\nAnswer: {answer}\n\n"
|
|
175
|
+
"Notes:\n" + ("\n".join(f"- {n}" for n in notes or ()) or "(none)")}]}]
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _loose_call(client, messages, schema, timeout):
|
|
179
|
+
"""One metered non-strict call; options ride on the call, not the shared client, so concurrent calls keep theirs."""
|
|
180
|
+
options = {"timeout": timeout}
|
|
181
|
+
if getattr(client, "per_call_reasoning", False) is True:
|
|
182
|
+
options["reasoning"] = "none"
|
|
183
|
+
if getattr(client, "per_call_strict", False) is True:
|
|
184
|
+
options["strict"] = False
|
|
185
|
+
out, _ = client.complete(messages, schema, **options)
|
|
186
|
+
return out or {}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def call_problem(error, limit=160):
|
|
190
|
+
"""Why a structuring call failed, cut to ``limit``; an empty account, read on the whole error, keeps its code."""
|
|
191
|
+
text = f"{type(error).__name__}: {error}"
|
|
192
|
+
if out_of_credit(text):
|
|
193
|
+
status = PROVIDER_ERROR.search(text)
|
|
194
|
+
code = next((code for code in CREDIT_CODES + ANTHROPIC_CREDIT if code in text), None)
|
|
195
|
+
return ": ".join(part for part in (type(error).__name__, status and status.group(0), code) if part)
|
|
196
|
+
return text[:limit]
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def structure_note(output_format, problem):
|
|
200
|
+
name = AUTOMATIC_FORMATS[output_format]
|
|
201
|
+
if out_of_credit(problem):
|
|
202
|
+
return (
|
|
203
|
+
f"Your {account_name(credit_provider(problem))} account ran out of credit before Mobster could turn this "
|
|
204
|
+
f"answer into {name}, so it’s shown as text.")
|
|
205
|
+
return f"Mobster couldn’t turn this answer into {name}, so it’s shown as text."
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def structure(client, request, answer, notes, schema, *, timeout=60):
|
|
209
|
+
"""(data, None) with the answer as data matching the user's JSON schema, validated, or (None, why)."""
|
|
210
|
+
from jsonschema import Draft202012Validator
|
|
211
|
+
wrapped = {"type": "object", "additionalProperties": False, "required": ["data"], "properties": {"data": schema}}
|
|
212
|
+
try:
|
|
213
|
+
value = _loose_call(client, _findings(request, answer, notes, "Put the phone agent's findings into the "
|
|
214
|
+
"requested structure."), wrapped, timeout).get("data")
|
|
215
|
+
except Exception as error:
|
|
216
|
+
return None, call_problem(error)
|
|
217
|
+
if any(True for _ in Draft202012Validator(schema).iter_errors(value)):
|
|
218
|
+
return None, "The answer did not fit the requested schema."
|
|
219
|
+
return value, None
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
AUTOMATIC_FORMATS = {"csv": "CSV", "json": "JSON", "yaml": "YAML"}
|
|
223
|
+
# The automatic structure's one call: the findings as named columns and rows. Code turns them into records with a
|
|
224
|
+
# schema, the shapes Fast's automatic output takes (output_contract.validate_automatic_schema): one flat record, or
|
|
225
|
+
# a list of them, which is also what CSV needs.
|
|
226
|
+
TABLE = {"type": "object", "additionalProperties": False, "required": ["columns", "rows", "single"], "properties": {
|
|
227
|
+
"columns": {"type": "array", "maxItems": 40, "items": {"type": "string"}},
|
|
228
|
+
"rows": {"type": "array", "maxItems": 100,
|
|
229
|
+
"items": {"type": "array", "items": {"type": ["string", "number", "boolean", "null"]}}},
|
|
230
|
+
"single": {"type": "boolean"}}}
|
|
231
|
+
CELL = ("string", "number", "integer", "boolean", "null")
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def structure_auto(client, request, answer, notes, output_format, *, timeout=60):
|
|
235
|
+
instruction = (f"Put the phone agent's findings into a table for a {AUTOMATIC_FORMATS[output_format]} export. "
|
|
236
|
+
"columns: one short, readable name per field, lower case, like title or due_date. rows: one row "
|
|
237
|
+
"per item the request asks about, one value per column in the same order. single: true when the "
|
|
238
|
+
"answer is about one thing, false for a list of things.")
|
|
239
|
+
try:
|
|
240
|
+
out = _loose_call(client, _findings(request, answer, notes, instruction), TABLE, timeout)
|
|
241
|
+
except Exception as error:
|
|
242
|
+
return None, None, call_problem(error)
|
|
243
|
+
return table_records(out, output_format)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def table_records(out, output_format):
|
|
247
|
+
from jsonschema import Draft202012Validator
|
|
248
|
+
|
|
249
|
+
from .output_contract import validate_automatic_schema
|
|
250
|
+
if not isinstance(out, dict):
|
|
251
|
+
return None, None, "The answer did not come back as a table."
|
|
252
|
+
columns, rows, single = out.get("columns"), out.get("rows"), out.get("single") is True
|
|
253
|
+
if not isinstance(columns, list) or not isinstance(rows, list) or not all(isinstance(row, list) for row in rows):
|
|
254
|
+
return None, None, "The answer did not come back as a table."
|
|
255
|
+
columns = [" ".join(str(name).split())[:64] for name in columns]
|
|
256
|
+
if not columns or not all(columns) or len(set(columns)) != len(columns) \
|
|
257
|
+
or any(len(row) != len(columns) for row in rows) or single and len(rows) != 1:
|
|
258
|
+
return None, None, "The table's columns and rows did not line up."
|
|
259
|
+
record = {"type": "object", "additionalProperties": False, "required": list(columns),
|
|
260
|
+
"properties": {name: {"type": list(CELL)} for name in columns}}
|
|
261
|
+
schema = record if single else {"type": "array", "maxItems": 100, "items": record}
|
|
262
|
+
records = [dict(zip(columns, row)) for row in rows]
|
|
263
|
+
data = records[0] if single else records
|
|
264
|
+
try:
|
|
265
|
+
validate_automatic_schema(output_format, schema) # its copy sorts the keys: the columns keep their order
|
|
266
|
+
except ValueError as error:
|
|
267
|
+
return None, None, str(error)
|
|
268
|
+
if any(True for _ in Draft202012Validator(schema).iter_errors(data)):
|
|
269
|
+
return None, None, "The table's values did not fit its columns."
|
|
270
|
+
return data, schema, None
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def shaped_answer(text, schema):
|
|
274
|
+
"""The DONE turn's data_json parsed, when it validates against the user's ``schema``; else None."""
|
|
275
|
+
if schema is None or not isinstance(text, str) or not text.strip():
|
|
276
|
+
return None
|
|
277
|
+
try:
|
|
278
|
+
value = json.loads(text)
|
|
279
|
+
from jsonschema import Draft202012Validator
|
|
280
|
+
if any(True for _ in Draft202012Validator(schema).iter_errors(value)):
|
|
281
|
+
return None
|
|
282
|
+
except Exception:
|
|
283
|
+
return None
|
|
284
|
+
return value
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def untouched_writes(contract):
|
|
288
|
+
"""WRITE items counted done though nothing was typed in their app: the model judged the text already there."""
|
|
289
|
+
from . import contract_screen as KS
|
|
290
|
+
if contract is None:
|
|
291
|
+
return []
|
|
292
|
+
|
|
293
|
+
def touched(item, typed):
|
|
294
|
+
if not contract._app_ok(item, typed["app"]):
|
|
295
|
+
return False
|
|
296
|
+
if not typed["search"]:
|
|
297
|
+
return True
|
|
298
|
+
return (bool(item.payload) and KS.overlaps(item.payload, typed["text"])
|
|
299
|
+
or bool(KS.SEARCHY.search(item.what)) or KS.overlaps(item.what, typed["text"]))
|
|
300
|
+
return [item for item in contract.items if item.kind == "WRITE" and not item.unproven and not any(
|
|
301
|
+
touched(item, t) for t in contract.typed)]
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def summarize(outcome, agent, events, *, request, output_format="auto", output_schema=None, cost_usd=None,
|
|
305
|
+
report=None, markdown=None):
|
|
306
|
+
if report is not None:
|
|
307
|
+
return _summarize_report(outcome, agent, events, request=request, output_format=output_format,
|
|
308
|
+
output_schema=output_schema, cost_usd=cost_usd, report=report, markdown=markdown)
|
|
309
|
+
contract = getattr(agent, "_contract", None)
|
|
310
|
+
raw_status = outcome.get("status") or "error"
|
|
311
|
+
status = STATUS.get(raw_status, "error")
|
|
312
|
+
full = (outcome.get("answer") or "").strip() or None
|
|
313
|
+
kind = outcome_of(status, contract, full)
|
|
314
|
+
untouched = untouched_writes(contract) if kind == "done" else []
|
|
315
|
+
if untouched:
|
|
316
|
+
kind = "check"
|
|
317
|
+
if status == "completed" and kind == "check":
|
|
318
|
+
status = "completion_not_confirmed"
|
|
319
|
+
model = getattr(getattr(agent, "client", None), "model", None) or smart_model()
|
|
320
|
+
reason = reason_of(status, kind, outcome.get("reason"), contract,
|
|
321
|
+
bool(getattr(getattr(agent, "client", None), "model_failed", False)) and status == "error",
|
|
322
|
+
model)
|
|
323
|
+
if untouched:
|
|
324
|
+
reason = "Already done, so Mobster changed nothing: " + "; ".join(item_text(i) for i in untouched[:3]) + "."
|
|
325
|
+
proof = events.final_proof() if events is not None else []
|
|
326
|
+
# The answer is its first sentence, a headline (the dashboard shows the rest of ``data`` under it). Only a
|
|
327
|
+
# sentence about what the agent did loses its "I"; words read on the phone stay as they were.
|
|
328
|
+
said = without_first_person(full) if full and tells_what_it_did(first_sentence(full), contract, proof) else full
|
|
329
|
+
summary = {"event": "result", "status": status, "engine": SMART, "outcome": kind,
|
|
330
|
+
"answer": first_sentence(said), "reason": reason, "independently_verified": kind == "done",
|
|
331
|
+
"actions": outcome.get("actions"), "decisions": outcome.get("steps"),
|
|
332
|
+
"elapsed_ms": round(outcome["elapsed"] * 1000) if outcome.get("elapsed") is not None else None,
|
|
333
|
+
"costUsd": cost_usd if cost_usd is not None else outcome.get("cost_usd"),
|
|
334
|
+
"model": model, "contract": outcome.get("contract"),
|
|
335
|
+
"timing": outcome.get("timing"), "proof": proof}
|
|
336
|
+
program = outcome.get("program")
|
|
337
|
+
if isinstance(program, dict) and program.get("replayed"):
|
|
338
|
+
# A saved or taught program ran steps with no model: the Mac app says "Learned" (lib/replay.ts runProgram).
|
|
339
|
+
summary["program"] = {key: program.get(key) for key in ("steps", "replayed", "status", "taught", "name",
|
|
340
|
+
"trusted", "helped", "practice", "corrections",
|
|
341
|
+
"first")}
|
|
342
|
+
if outcome.get("code"):
|
|
343
|
+
summary["code"] = outcome["code"]
|
|
344
|
+
if outcome["code"] in STOP_CODES:
|
|
345
|
+
# The field a Quick run and a refused preflight carry too: the reason is the phone's own sentence.
|
|
346
|
+
summary["stop_code"] = outcome["code"]
|
|
347
|
+
if status == "error":
|
|
348
|
+
failed = model_error(outcome.get("reason"),
|
|
349
|
+
bool(getattr(getattr(agent, "client", None), "model_failed", False)))
|
|
350
|
+
if failed:
|
|
351
|
+
summary["model_error"] = failed
|
|
352
|
+
automatic = output_schema is None and output_format in AUTOMATIC_FORMATS
|
|
353
|
+
if full and status in ("completed", "completion_not_confirmed", "spend_cap", "max_steps", "timeout", "blocked"):
|
|
354
|
+
if (output_schema is not None or automatic) and status != "blocked":
|
|
355
|
+
client = getattr(agent, "client", None)
|
|
356
|
+
# The DONE turn's own data_json, when it fits the schema (or is a valid table), needs no structuring call.
|
|
357
|
+
given = shaped_answer(outcome.get("data_json"), TABLE if automatic else output_schema)
|
|
358
|
+
data, schema, problem = (table_records(given, output_format) if automatic
|
|
359
|
+
else (given, output_schema, None))
|
|
360
|
+
if data is None:
|
|
361
|
+
if client is None:
|
|
362
|
+
problem = "No model client"
|
|
363
|
+
elif automatic:
|
|
364
|
+
data, schema, problem = structure_auto(client, request, full, outcome.get("notes"), output_format)
|
|
365
|
+
else:
|
|
366
|
+
data, problem = structure(client, request, full, outcome.get("notes"), output_schema)
|
|
367
|
+
schema = output_schema
|
|
368
|
+
source = "automatic" if automatic else "custom"
|
|
369
|
+
if data is not None:
|
|
370
|
+
summary.update(data=data, resolved_output_format=output_format, schema_validated=True,
|
|
371
|
+
data_status="validated", output_schema=schema, schema_source=source, full_answer=full)
|
|
372
|
+
lead = lead_sentence(said, data)
|
|
373
|
+
if lead:
|
|
374
|
+
summary["answer"] = lead
|
|
375
|
+
elif automatic:
|
|
376
|
+
# The answer stands without a structure: its text, with a line that says why it isn't the format.
|
|
377
|
+
summary.update(data=full, resolved_output_format="text", data_status="observed", full_answer=full,
|
|
378
|
+
structure_error=problem, output_note=structure_note(output_format, problem))
|
|
379
|
+
else:
|
|
380
|
+
summary.update(data_status="schema_validation_failed", resolved_output_format=output_format,
|
|
381
|
+
full_answer=full, structure_error=problem, schema_source=source)
|
|
382
|
+
if out_of_credit(problem):
|
|
383
|
+
summary["output_note"] = (
|
|
384
|
+
f"Your {account_name(credit_provider(problem))} account ran out of credit before "
|
|
385
|
+
"Mobster could fit this answer to your schema.")
|
|
386
|
+
else:
|
|
387
|
+
summary.update(data=full, resolved_output_format="markdown" if output_format == "markdown" else "text",
|
|
388
|
+
data_status="observed")
|
|
389
|
+
if output_format == "auto":
|
|
390
|
+
# Tables and check lines in the answer are result blocks (answer_shapes.from_answer); the text keeps
|
|
391
|
+
# the rest, Copy keeps it all (full_answer), and the headline is the rest's first sentence.
|
|
392
|
+
from .answer_shapes import from_answer
|
|
393
|
+
from .result_blocks import envelope
|
|
394
|
+
rest, found = from_answer(full, request)
|
|
395
|
+
blocks = envelope(found) if found else None
|
|
396
|
+
if blocks is not None:
|
|
397
|
+
summary.update(blocks=blocks, data=rest or None, full_answer=full)
|
|
398
|
+
if rest:
|
|
399
|
+
said_rest = without_first_person(rest) if tells_what_it_did(first_sentence(rest), contract,
|
|
400
|
+
proof) else rest
|
|
401
|
+
summary["answer"] = first_sentence(said_rest)
|
|
402
|
+
else:
|
|
403
|
+
summary["answer"] = blocks["blocks"][0].get("title") or "Here\u2019s what Mobster found."
|
|
404
|
+
else:
|
|
405
|
+
summary.update(resolved_output_format=None,
|
|
406
|
+
output_intent="action_only" if full is None and kind == "done" else None)
|
|
407
|
+
if not full and kind == "done":
|
|
408
|
+
summary["answer"] = "Done."
|
|
409
|
+
tool_blocks = tool_envelope(events, status, output_schema)
|
|
410
|
+
if tool_blocks is not None:
|
|
411
|
+
from .result_blocks import merge
|
|
412
|
+
# What tools read comes first (an app pack's DM rows, its Reels); the answer's own cards follow.
|
|
413
|
+
answer_blocks = [b for b in (summary.get("blocks") or {}).get("blocks") or ()
|
|
414
|
+
if not repeats_tool_rows(b, tool_blocks["blocks"])]
|
|
415
|
+
merged = merge(tool_blocks, {"blocks": answer_blocks})
|
|
416
|
+
if merged is not None:
|
|
417
|
+
summary["blocks"] = merged
|
|
418
|
+
return summary
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def _cell_words(value):
|
|
422
|
+
return " ".join(str(value or "").split()).casefold().lstrip("@")
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def repeats_tool_rows(block, tool_blocks):
|
|
426
|
+
if not isinstance(block, dict) or block.get("type") != "table":
|
|
427
|
+
return False
|
|
428
|
+
columns = block.get("columns") or ()
|
|
429
|
+
first = columns[0].get("key") if columns and isinstance(columns[0], dict) else None
|
|
430
|
+
values = [_cell_words((row.get("cells") or {}).get(first)) for row in block.get("rows") or ()
|
|
431
|
+
if isinstance(row, dict)]
|
|
432
|
+
values = [v for v in values if v and not v.isdigit()]
|
|
433
|
+
if not values:
|
|
434
|
+
return False
|
|
435
|
+
for tool in tool_blocks:
|
|
436
|
+
held = set()
|
|
437
|
+
for row in tool.get("rows") or ():
|
|
438
|
+
held.update(_cell_words(v) for v in (row.get("cells") or {}).values())
|
|
439
|
+
for item in tool.get("items") or ():
|
|
440
|
+
held.update(_cell_words(item.get(k)) for k in ("title", "creator", "to"))
|
|
441
|
+
if sum(1 for v in values if v in held) >= max(2, .6 * len(values)):
|
|
442
|
+
return True
|
|
443
|
+
return False
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def tool_envelope(events, status, output_schema):
|
|
447
|
+
blocks = list(getattr(events, "tool_blocks", None) or ())
|
|
448
|
+
if not blocks or output_schema is not None or status in ("stopped", "approval_denied", "approval_timeout",
|
|
449
|
+
"error"):
|
|
450
|
+
return None
|
|
451
|
+
from .result_blocks import envelope
|
|
452
|
+
newest = {}
|
|
453
|
+
for block in blocks:
|
|
454
|
+
if isinstance(block, dict):
|
|
455
|
+
newest.pop(block.get("id"), None)
|
|
456
|
+
newest[block.get("id")] = block
|
|
457
|
+
return envelope(list(newest.values()))
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def _summarize_report(outcome, agent, events, *, request, output_format, output_schema, cost_usd, report, markdown):
|
|
461
|
+
"""``summarize`` for a long task with a report."""
|
|
462
|
+
tldr = " ".join(str(report.get("tldr") or "").split())
|
|
463
|
+
full = (markdown or "").strip() or None
|
|
464
|
+
partial = bool(report.get("partial"))
|
|
465
|
+
# The final report replaces the loop's answer, so its earlier DONE data cannot describe this export.
|
|
466
|
+
raw = {**outcome, "answer": full, "data_json": None}
|
|
467
|
+
if outcome.get("status") in ("max_steps", "timeout", "budget") and not partial:
|
|
468
|
+
raw["status"] = "completed"
|
|
469
|
+
summary = summarize(raw, agent, events, request=request, output_format=output_format, output_schema=output_schema,
|
|
470
|
+
cost_usd=cost_usd)
|
|
471
|
+
headline = first_sentence(tldr) if tldr else first_sentence(report.get("title"))
|
|
472
|
+
contract = getattr(agent, "_contract", None)
|
|
473
|
+
unproven = [i for i in (contract.unproven() if contract else ()) if i.kind in ("COMMIT", "WRITE")]
|
|
474
|
+
summary.update(answer=headline or summary.get("answer"), report=report, markdown=markdown,
|
|
475
|
+
outcome="check" if partial or unproven else "done")
|
|
476
|
+
# A report comes from a long task (longform/report.py), so its helpers are there whenever this runs.
|
|
477
|
+
helpers = harness_api.hooks().long_report()
|
|
478
|
+
if not summary.get("proof") and helpers is not None:
|
|
479
|
+
# What the report rests on, quoted as the screens showed it (the Mac app's proof).
|
|
480
|
+
summary["proof"] = helpers.proof(report, getattr(events, "apps", None))
|
|
481
|
+
if summary.get("status") == "completion_not_confirmed" and not partial and not unproven:
|
|
482
|
+
summary["status"] = "completed"
|
|
483
|
+
if partial:
|
|
484
|
+
summary["reason"] = (helpers.partial_line(report, None) if helpers else None) or summary.get("reason")
|
|
485
|
+
elif summary.get("reason") and summary.get("status") == "completed" and not unproven:
|
|
486
|
+
summary["reason"] = None
|
|
487
|
+
if full and output_schema is None and output_format not in AUTOMATIC_FORMATS:
|
|
488
|
+
summary.update(data=markdown, resolved_output_format="markdown", data_status="observed")
|
|
489
|
+
summary["independently_verified"] = False
|
|
490
|
+
return summary
|