minitap-mobile-use 2.2.0__py3-none-any.whl → 2.4.0__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.

Potentially problematic release.


This version of minitap-mobile-use might be problematic. Click here for more details.

Files changed (59) hide show
  1. minitap/mobile_use/agents/contextor/contextor.py +6 -4
  2. minitap/mobile_use/agents/cortex/cortex.md +114 -27
  3. minitap/mobile_use/agents/cortex/cortex.py +8 -5
  4. minitap/mobile_use/agents/executor/executor.md +15 -10
  5. minitap/mobile_use/agents/executor/executor.py +6 -5
  6. minitap/mobile_use/agents/executor/utils.py +2 -1
  7. minitap/mobile_use/agents/hopper/hopper.py +6 -3
  8. minitap/mobile_use/agents/orchestrator/orchestrator.py +26 -11
  9. minitap/mobile_use/agents/outputter/outputter.py +6 -3
  10. minitap/mobile_use/agents/outputter/test_outputter.py +104 -42
  11. minitap/mobile_use/agents/planner/planner.md +20 -22
  12. minitap/mobile_use/agents/planner/planner.py +10 -7
  13. minitap/mobile_use/agents/planner/types.py +4 -2
  14. minitap/mobile_use/agents/planner/utils.py +14 -0
  15. minitap/mobile_use/agents/summarizer/summarizer.py +2 -2
  16. minitap/mobile_use/config.py +6 -1
  17. minitap/mobile_use/context.py +13 -3
  18. minitap/mobile_use/controllers/mobile_command_controller.py +1 -14
  19. minitap/mobile_use/graph/state.py +7 -3
  20. minitap/mobile_use/sdk/agent.py +204 -29
  21. minitap/mobile_use/sdk/examples/README.md +19 -1
  22. minitap/mobile_use/sdk/examples/platform_minimal_example.py +46 -0
  23. minitap/mobile_use/sdk/services/platform.py +244 -0
  24. minitap/mobile_use/sdk/types/__init__.py +14 -14
  25. minitap/mobile_use/sdk/types/exceptions.py +57 -0
  26. minitap/mobile_use/sdk/types/platform.py +125 -0
  27. minitap/mobile_use/sdk/types/task.py +60 -17
  28. minitap/mobile_use/servers/device_hardware_bridge.py +3 -2
  29. minitap/mobile_use/servers/stop_servers.py +11 -12
  30. minitap/mobile_use/servers/utils.py +6 -9
  31. minitap/mobile_use/services/llm.py +89 -5
  32. minitap/mobile_use/tools/index.py +2 -8
  33. minitap/mobile_use/tools/mobile/back.py +3 -3
  34. minitap/mobile_use/tools/mobile/clear_text.py +67 -38
  35. minitap/mobile_use/tools/mobile/erase_one_char.py +5 -4
  36. minitap/mobile_use/tools/mobile/{take_screenshot.py → glimpse_screen.py} +23 -15
  37. minitap/mobile_use/tools/mobile/input_text.py +67 -16
  38. minitap/mobile_use/tools/mobile/launch_app.py +54 -22
  39. minitap/mobile_use/tools/mobile/long_press_on.py +15 -8
  40. minitap/mobile_use/tools/mobile/open_link.py +15 -8
  41. minitap/mobile_use/tools/mobile/press_key.py +15 -8
  42. minitap/mobile_use/tools/mobile/stop_app.py +14 -8
  43. minitap/mobile_use/tools/mobile/swipe.py +11 -5
  44. minitap/mobile_use/tools/mobile/tap.py +103 -21
  45. minitap/mobile_use/tools/mobile/wait_for_animation_to_end.py +3 -3
  46. minitap/mobile_use/tools/test_utils.py +377 -0
  47. minitap/mobile_use/tools/types.py +35 -0
  48. minitap/mobile_use/tools/utils.py +149 -39
  49. minitap/mobile_use/utils/recorder.py +1 -1
  50. minitap/mobile_use/utils/test_ui_hierarchy.py +178 -0
  51. minitap/mobile_use/utils/ui_hierarchy.py +11 -4
  52. {minitap_mobile_use-2.2.0.dist-info → minitap_mobile_use-2.4.0.dist-info}/METADATA +6 -4
  53. minitap_mobile_use-2.4.0.dist-info/RECORD +99 -0
  54. minitap/mobile_use/tools/mobile/copy_text_from.py +0 -73
  55. minitap/mobile_use/tools/mobile/find_packages.py +0 -69
  56. minitap/mobile_use/tools/mobile/paste_text.py +0 -62
  57. minitap_mobile_use-2.2.0.dist-info/RECORD +0 -96
  58. {minitap_mobile_use-2.2.0.dist-info → minitap_mobile_use-2.4.0.dist-info}/WHEEL +0 -0
  59. {minitap_mobile_use-2.2.0.dist-info → minitap_mobile_use-2.4.0.dist-info}/entry_points.txt +0 -0
@@ -3,23 +3,28 @@ import sys
3
3
  import tempfile
4
4
  import time
5
5
  import uuid
6
- from datetime import datetime
6
+ from collections.abc import Callable, Coroutine
7
+ from datetime import UTC, datetime
7
8
  from pathlib import Path
9
+ from shutil import which
8
10
  from types import NoneType
9
- from typing import TypeVar, overload
11
+ from typing import Any, TypeVar, overload
10
12
 
11
13
  from adbutils import AdbClient
14
+ from dotenv import load_dotenv
12
15
  from langchain_core.messages import AIMessage
13
16
  from pydantic import BaseModel
14
17
 
15
18
  from minitap.mobile_use.agents.outputter.outputter import outputter
19
+ from minitap.mobile_use.agents.planner.types import Subgoal
16
20
  from minitap.mobile_use.clients.device_hardware_client import DeviceHardwareClient
17
21
  from minitap.mobile_use.clients.screen_api_client import ScreenApiClient
18
- from minitap.mobile_use.config import OutputConfig, record_events
22
+ from minitap.mobile_use.config import AgentNode, OutputConfig, record_events, settings
19
23
  from minitap.mobile_use.context import (
20
24
  DeviceContext,
21
25
  DevicePlatform,
22
26
  ExecutionSetup,
27
+ IsReplan,
23
28
  MobileUseContext,
24
29
  )
25
30
  from minitap.mobile_use.controllers.mobile_command_controller import (
@@ -31,19 +36,26 @@ from minitap.mobile_use.graph.graph import get_graph
31
36
  from minitap.mobile_use.graph.state import State
32
37
  from minitap.mobile_use.sdk.builders.agent_config_builder import get_default_agent_config
33
38
  from minitap.mobile_use.sdk.builders.task_request_builder import TaskRequestBuilder
34
- from minitap.mobile_use.sdk.constants import (
35
- DEFAULT_HW_BRIDGE_BASE_URL,
36
- DEFAULT_SCREEN_API_BASE_URL,
37
- )
39
+ from minitap.mobile_use.sdk.constants import DEFAULT_HW_BRIDGE_BASE_URL, DEFAULT_SCREEN_API_BASE_URL
40
+ from minitap.mobile_use.sdk.services.platform import PlatformService
38
41
  from minitap.mobile_use.sdk.types.agent import AgentConfig
39
42
  from minitap.mobile_use.sdk.types.exceptions import (
40
43
  AgentNotInitializedError,
41
44
  AgentProfileNotFoundError,
42
45
  AgentTaskRequestError,
43
46
  DeviceNotFoundError,
47
+ ExecutableNotFoundError,
48
+ PlatformServiceUninitializedError,
44
49
  ServerStartupError,
45
50
  )
46
- from minitap.mobile_use.sdk.types.task import AgentProfile, Task, TaskRequest, TaskStatus
51
+ from minitap.mobile_use.sdk.types.platform import TaskRunPlanResponse, TaskRunStatus
52
+ from minitap.mobile_use.sdk.types.task import (
53
+ AgentProfile,
54
+ PlatformTaskInfo,
55
+ PlatformTaskRequest,
56
+ Task,
57
+ TaskRequest,
58
+ )
47
59
  from minitap.mobile_use.servers.device_hardware_bridge import BridgeStatus
48
60
  from minitap.mobile_use.servers.start_servers import (
49
61
  start_device_hardware_bridge,
@@ -63,6 +75,8 @@ logger = get_logger(__name__)
63
75
 
64
76
  TOutput = TypeVar("TOutput", bound=BaseModel | None)
65
77
 
78
+ load_dotenv()
79
+
66
80
 
67
81
  class Agent:
68
82
  _config: AgentConfig
@@ -76,11 +90,23 @@ class Agent:
76
90
  _hw_bridge_client: DeviceHardwareClient
77
91
  _adb_client: AdbClient | None
78
92
 
79
- def __init__(self, config: AgentConfig | None = None):
93
+ def __init__(self, *, config: AgentConfig | None = None):
80
94
  self._config = config or get_default_agent_config()
81
95
  self._tasks = []
82
96
  self._tmp_traces_dir = Path(tempfile.gettempdir()) / "mobile-use-traces"
83
97
  self._initialized = False
98
+ self._is_default_hw_bridge = (
99
+ self._config.servers.hw_bridge_base_url == DEFAULT_HW_BRIDGE_BASE_URL
100
+ )
101
+ self._is_default_screen_api = (
102
+ self._config.servers.screen_api_base_url == DEFAULT_SCREEN_API_BASE_URL
103
+ )
104
+ # Initialize platform service if API key is available in environment
105
+ # Note: Can also be initialized later with API key from request
106
+ if settings.MINITAP_API_KEY:
107
+ self._platform_service = PlatformService()
108
+ else:
109
+ self._platform_service = None
84
110
 
85
111
  def init(
86
112
  self,
@@ -88,6 +114,11 @@ class Agent:
88
114
  retry_count: int = 5,
89
115
  retry_wait_seconds: int = 5,
90
116
  ):
117
+ if not which("adb") and not which("xcrun"):
118
+ raise ExecutableNotFoundError("cli_tools")
119
+ if self._is_default_hw_bridge and not which("maestro"):
120
+ raise ExecutableNotFoundError("maestro")
121
+
91
122
  if self._initialized:
92
123
  logger.warning("Agent is already initialized. Skipping...")
93
124
  return True
@@ -183,6 +214,12 @@ class Agent:
183
214
  @overload
184
215
  async def run_task(self, *, request: TaskRequest[TOutput]) -> TOutput | None: ...
185
216
 
217
+ @overload
218
+ async def run_task(self, *, request: PlatformTaskRequest[None]) -> str | dict | None: ...
219
+
220
+ @overload
221
+ async def run_task(self, *, request: PlatformTaskRequest[TOutput]) -> TOutput | None: ...
222
+
186
223
  async def run_task(
187
224
  self,
188
225
  *,
@@ -190,10 +227,25 @@ class Agent:
190
227
  output: type[TOutput] | str | None = None,
191
228
  profile: str | AgentProfile | None = None,
192
229
  name: str | None = None,
193
- request: TaskRequest[TOutput] | None = None,
230
+ request: TaskRequest[TOutput] | PlatformTaskRequest[TOutput] | None = None,
194
231
  ) -> str | dict | TOutput | None:
195
232
  if request is not None:
196
- return await self._run_task(request)
233
+ task_info = None
234
+ platform_service = None
235
+ if isinstance(request, PlatformTaskRequest):
236
+ # Initialize platform service with API key from request if provided
237
+ if request.api_key:
238
+ platform_service = PlatformService(api_key=request.api_key)
239
+ elif self._platform_service:
240
+ platform_service = self._platform_service
241
+ else:
242
+ raise PlatformServiceUninitializedError()
243
+ task_info = await platform_service.create_task_run(request=request)
244
+ self._config.agent_profiles[task_info.llm_profile.name] = task_info.llm_profile
245
+ request = task_info.task_request
246
+ return await self._run_task(
247
+ request=request, task_info=task_info, platform_service=platform_service
248
+ )
197
249
  if goal is None:
198
250
  raise AgentTaskRequestError("Goal is required")
199
251
  task_request = self.new_task(goal=goal)
@@ -208,7 +260,12 @@ class Agent:
208
260
  task_request.with_name(name=name)
209
261
  return await self._run_task(task_request.build())
210
262
 
211
- async def _run_task(self, request: TaskRequest[TOutput]) -> str | dict | TOutput | None:
263
+ async def _run_task(
264
+ self,
265
+ request: TaskRequest[TOutput],
266
+ task_info: PlatformTaskInfo | None = None,
267
+ platform_service: PlatformService | None = None,
268
+ ) -> str | dict | TOutput | None:
212
269
  if not self._initialized:
213
270
  raise AgentNotInitializedError()
214
271
 
@@ -220,22 +277,48 @@ class Agent:
220
277
  agent_profile = self._config.default_profile
221
278
  logger.info(str(agent_profile))
222
279
 
280
+ on_status_changed = None
281
+ on_agent_thought = None
282
+ on_plan_changes = None
283
+ task_id = str(uuid.uuid4())
284
+ if task_info:
285
+ on_status_changed = self._get_task_status_change_callback(
286
+ task_info=task_info, platform_service=platform_service
287
+ )
288
+ on_agent_thought = self._get_new_agent_thought_callback(
289
+ task_info=task_info, platform_service=platform_service
290
+ )
291
+ on_plan_changes = self._get_plan_changes_callback(
292
+ task_info=task_info, platform_service=platform_service
293
+ )
294
+ task_id = task_info.task_run.id
295
+
223
296
  task = Task(
224
- id=str(uuid.uuid4()),
297
+ id=task_id,
225
298
  device=self._device_context,
226
- status=TaskStatus.PENDING,
299
+ status="pending",
227
300
  request=request,
228
301
  created_at=datetime.now(),
302
+ on_status_changed=on_status_changed,
229
303
  )
230
304
  self._tasks.append(task)
231
305
  task_name = task.get_name()
232
306
 
307
+ # Extract API key from platform service if available
308
+ api_key = None
309
+ if platform_service:
310
+ api_key = platform_service._api_key
311
+
233
312
  context = MobileUseContext(
313
+ trace_id=task.id,
234
314
  device=self._device_context,
235
315
  hw_bridge_client=self._hw_bridge_client,
236
316
  screen_api_client=self._screen_api_client,
237
317
  adb_client=self._adb_client,
238
318
  llm_config=agent_profile.llm_config,
319
+ on_agent_thought=on_agent_thought,
320
+ on_plan_changes=on_plan_changes,
321
+ minitap_api_key=api_key,
239
322
  )
240
323
 
241
324
  self._prepare_tracing(task=task, context=context)
@@ -258,7 +341,7 @@ class Agent:
258
341
  output = None
259
342
  try:
260
343
  logger.info(f"[{task_name}] Invoking graph with input: {graph_input}")
261
- task.status = TaskStatus.RUNNING
344
+ await task.set_status(status="running", message="Invoking graph...")
262
345
  async for chunk in (await get_graph(context)).astream(
263
346
  input=graph_input,
264
347
  config={
@@ -290,7 +373,7 @@ class Agent:
290
373
  if not last_state:
291
374
  err = f"[{task_name}] No result received from graph"
292
375
  logger.warning(err)
293
- task.finalize(content=output, state=last_state_snapshot, error=err)
376
+ await task.finalize(content=output, state=last_state_snapshot, error=err)
294
377
  return None
295
378
 
296
379
  print_ai_response_to_stderr(graph_result=last_state)
@@ -302,16 +385,25 @@ class Agent:
302
385
  state=last_state,
303
386
  )
304
387
  logger.info(f"✅ Automation '{task_name}' is success ✅")
305
- task.finalize(content=output, state=last_state_snapshot)
388
+ await task.finalize(content=output, state=last_state_snapshot)
306
389
  except asyncio.CancelledError:
307
390
  err = f"[{task_name}] Task cancelled"
308
391
  logger.warning(err)
309
- task.finalize(content=output, state=last_state_snapshot, error=err, cancelled=True)
392
+ await task.finalize(
393
+ content=output,
394
+ state=last_state_snapshot,
395
+ error=err,
396
+ cancelled=True,
397
+ )
310
398
  raise
311
399
  except Exception as e:
312
400
  err = f"[{task_name}] Error running automation: {e}"
313
401
  logger.error(err)
314
- task.finalize(content=output, state=last_state_snapshot, error=err)
402
+ await task.finalize(
403
+ content=output,
404
+ state=last_state_snapshot,
405
+ error=err,
406
+ )
315
407
  raise
316
408
  finally:
317
409
  self._finalize_tracing(task=task, context=context)
@@ -342,7 +434,9 @@ class Agent:
342
434
  traces_output_path.mkdir(parents=True, exist_ok=True)
343
435
  temp_trace_path.mkdir(parents=True, exist_ok=True)
344
436
  context.execution_setup = ExecutionSetup(
345
- traces_path=self._tmp_traces_dir, trace_id=task_name
437
+ traces_path=self._tmp_traces_dir,
438
+ trace_name=task_name,
439
+ enable_remote_tracing=task.request.enable_remote_tracing,
346
440
  )
347
441
 
348
442
  def _finalize_tracing(self, task: Task, context: MobileUseContext):
@@ -351,11 +445,11 @@ class Agent:
351
445
  return
352
446
 
353
447
  task_name = task.get_name()
354
- status = "_PASS" if task.status == TaskStatus.COMPLETED else "_FAIL"
448
+ status = "_PASS" if task.status == "completed" else "_FAIL"
355
449
  ts = task.created_at.strftime("%Y-%m-%dT%H-%M-%S")
356
- new_name = f"{exec_setup_ctx.trace_id}{status}_{ts}"
450
+ new_name = f"{exec_setup_ctx.trace_name}{status}_{ts}"
357
451
 
358
- temp_trace_path = (self._tmp_traces_dir / exec_setup_ctx.trace_id).resolve()
452
+ temp_trace_path = (self._tmp_traces_dir / exec_setup_ctx.trace_name).resolve()
359
453
  traces_output_path = Path(task.request.trace_path).resolve()
360
454
 
361
455
  logger.info(f"[{task_name}] Compiling trace FROM FOLDER: " + str(temp_trace_path))
@@ -433,17 +527,11 @@ class Agent:
433
527
  self._hw_bridge_client = DeviceHardwareClient(
434
528
  base_url=self._config.servers.hw_bridge_base_url.to_url(),
435
529
  )
436
- self._is_default_hw_bridge = (
437
- self._config.servers.hw_bridge_base_url == DEFAULT_HW_BRIDGE_BASE_URL
438
- )
439
530
  self._screen_api_client = ScreenApiClient(
440
531
  base_url=self._config.servers.screen_api_base_url.to_url(),
441
532
  retry_count=retry_count,
442
533
  retry_wait_seconds=retry_wait_seconds,
443
534
  )
444
- self._is_default_screen_api = (
445
- self._config.servers.screen_api_base_url == DEFAULT_SCREEN_API_BASE_URL
446
- )
447
535
 
448
536
  def _run_servers(self, device_id: str, platform: DevicePlatform) -> bool:
449
537
  if self._is_default_hw_bridge:
@@ -496,7 +584,10 @@ class Agent:
496
584
 
497
585
  def _check_device_screen_api_health(self) -> bool:
498
586
  try:
587
+ # Required to know if the Screen API is up
499
588
  self._screen_api_client.get_with_retry("/health", timeout=5)
589
+ # Required to know if the Screen API actually receives screenshot from the HW Bridge API
590
+ self._screen_api_client.get_with_retry("/screen-info", timeout=5)
500
591
  return True
501
592
  except Exception as e:
502
593
  logger.error(f"Device Screen API health check failed: {e}")
@@ -519,6 +610,90 @@ class Agent:
519
610
  device_height=screen_data.height,
520
611
  )
521
612
 
613
+ def _get_task_status_change_callback(
614
+ self,
615
+ task_info: PlatformTaskInfo,
616
+ platform_service: PlatformService | None = None,
617
+ ) -> Callable[[TaskRunStatus, str | None, Any | None], Coroutine]:
618
+ service = platform_service or self._platform_service
619
+
620
+ async def change_status(
621
+ status: TaskRunStatus,
622
+ message: str | None = None,
623
+ output: Any | None = None,
624
+ ):
625
+ if not service:
626
+ raise PlatformServiceUninitializedError()
627
+ try:
628
+ await service.update_task_run_status(
629
+ task_run_id=task_info.task_run.id,
630
+ status=status,
631
+ message=message,
632
+ output=output,
633
+ )
634
+ except Exception as e:
635
+ logger.error(f"Failed to update task run status: {e}")
636
+
637
+ return change_status
638
+
639
+ def _get_plan_changes_callback(
640
+ self,
641
+ task_info: PlatformTaskInfo,
642
+ platform_service: PlatformService | None = None,
643
+ ) -> Callable[[list[Subgoal], IsReplan], Coroutine]:
644
+ service = platform_service or self._platform_service
645
+ current_plan: TaskRunPlanResponse | None = None
646
+
647
+ async def update_plan(plan: list[Subgoal], is_replan: IsReplan):
648
+ nonlocal current_plan
649
+
650
+ if not service:
651
+ raise PlatformServiceUninitializedError()
652
+ try:
653
+ if is_replan and current_plan:
654
+ # End previous plan
655
+ await service.upsert_task_run_plan(
656
+ task_run_id=task_info.task_run.id,
657
+ started_at=current_plan.started_at,
658
+ plan=plan,
659
+ ended_at=datetime.now(UTC),
660
+ plan_id=current_plan.id,
661
+ )
662
+ current_plan = None
663
+
664
+ current_plan = await service.upsert_task_run_plan(
665
+ task_run_id=task_info.task_run.id,
666
+ started_at=current_plan.started_at if current_plan else datetime.now(UTC),
667
+ plan=plan,
668
+ ended_at=current_plan.ended_at if current_plan else None,
669
+ plan_id=current_plan.id if current_plan else None,
670
+ )
671
+ except Exception as e:
672
+ logger.error(f"Failed to update plan: {e}")
673
+
674
+ return update_plan
675
+
676
+ def _get_new_agent_thought_callback(
677
+ self,
678
+ task_info: PlatformTaskInfo,
679
+ platform_service: PlatformService | None = None,
680
+ ) -> Callable[[AgentNode, str], Coroutine]:
681
+ service = platform_service or self._platform_service
682
+
683
+ async def add_agent_thought(agent: AgentNode, thought: str):
684
+ if not service:
685
+ raise PlatformServiceUninitializedError()
686
+ try:
687
+ await service.add_agent_thought(
688
+ task_run_id=task_info.task_run.id,
689
+ agent=agent,
690
+ thought=thought,
691
+ )
692
+ except Exception as e:
693
+ logger.error(f"Failed to add agent thought: {e}")
694
+
695
+ return add_agent_thought
696
+
522
697
 
523
698
  def _validate_and_prepare_file(file_path: Path):
524
699
  path_obj = Path(file_path)
@@ -3,12 +3,26 @@
3
3
  Location: `src/mobile_use/sdk/examples/`
4
4
 
5
5
  Run any example via:
6
+
6
7
  - `python src/mobile_use/sdk/examples/<filename>.py`
7
8
 
8
9
  ## Practical Automation Examples
9
10
 
10
11
  These examples demonstrate two different ways to use the SDK, each applying an appropriate level of complexity for the task at hand:
11
12
 
13
+ ### platform_minimal_example.py - Painless integration with the Minitap platform
14
+
15
+ This script shows the simplest way to run minitap :
16
+
17
+ - Visit https://platform.minitap.ai to create a task and get your API key.
18
+ - Initialize the agent with your API key: Agent(minitap_api_key=...).
19
+ - Ask the agent to run one of the tasks you’ve set up in the Minitap platform
20
+ (e.g., "like-instagram-post").
21
+ - The task’s goal and settings live in the Minitap platform, you don’t need
22
+ to hardcode them here.
23
+ - If you’ve created different profiles (LLM configurations) in the Minitap platform (like "fast-config"),
24
+ you can pick which one to use with the `profile` field.
25
+
12
26
  ### simple_photo_organizer.py - Straightforward Approach
13
27
 
14
28
  Demonstrates the simplest way to use the SDK for quick automation tasks:
@@ -32,7 +46,11 @@ Showcases more advanced SDK features while remaining practical:
32
46
 
33
47
  ## Usage Notes
34
48
 
35
- - **Choosing an Approach**: Use the direct approach (like in `simple_photo_organizer.py`) for simple tasks and the builder approach (like in `smart_notification_assistant.py`) when you need more customization.
49
+ - **Choosing an Approach**:
50
+
51
+ - Use the direct approach (like `platform_minimal_example.py`) for painless setup using the Minitap platform. You can configure any task, save, run, and monitor them with a few clicks.
52
+ - Use the simple approach (like `simple_photo_organizer.py`) for straightforward tasks, you configure settings yourself and every LLM call happens on your device.
53
+ - Use the builder approach (like `smart_notification_assistant.py`) when you need more customization.
36
54
 
37
55
  - **Device Detection**: The agent detects the first available device unless you specify one with `AgentConfigBuilder.for_device(...)`.
38
56
 
@@ -0,0 +1,46 @@
1
+ """
2
+ Platform Usage - Minitap SDK with API Key Example
3
+
4
+ This example demonstrates how to use the mobile-use SDK via the Minitap platform:
5
+ - Agent with minitap_api_key
6
+ - PlatformTaskRequest with platform-provided task_id
7
+ - All task configuration (goal, output format, etc.) managed by platform UI
8
+
9
+ Platform Model:
10
+ - API key provides authentication and agent configuration
11
+ - task_id references pre-configured task from platform UI
12
+ - No goal, output_format, profile selection needed in code
13
+ - Everything bound to task_id + api_key combination
14
+
15
+ Run:
16
+ - python src/mobile_use/sdk/examples/platform_minimal_example.py
17
+ """
18
+
19
+ import asyncio
20
+
21
+ from minitap.mobile_use.sdk import Agent
22
+ from minitap.mobile_use.sdk.types import PlatformTaskRequest
23
+
24
+
25
+ async def main() -> None:
26
+ """
27
+ Main execution function demonstrating minitap platform usage pattern.
28
+
29
+ Visit https://platform.minitap.ai to create a task, customize your profiles,
30
+ and get your API key.
31
+ Set MINITAP_API_KEY and MINITAP_API_BASE_URL environment variables.
32
+ """
33
+ agent = Agent()
34
+ agent.init()
35
+ result = await agent.run_task(
36
+ request=PlatformTaskRequest(
37
+ task="your-task-name",
38
+ profile="your-profile-name",
39
+ )
40
+ )
41
+ print(result)
42
+ agent.clean()
43
+
44
+
45
+ if __name__ == "__main__":
46
+ asyncio.run(main())