minitap-mobile-use 2.0.1__py3-none-any.whl → 2.1.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 (60) hide show
  1. minitap/mobile_use/agents/cortex/cortex.md +7 -5
  2. minitap/mobile_use/agents/cortex/cortex.py +4 -1
  3. minitap/mobile_use/agents/cortex/types.py +1 -3
  4. minitap/mobile_use/agents/executor/executor.md +4 -5
  5. minitap/mobile_use/agents/executor/tool_node.py +6 -6
  6. minitap/mobile_use/agents/outputter/outputter.py +1 -2
  7. minitap/mobile_use/agents/planner/planner.md +11 -2
  8. minitap/mobile_use/agents/planner/planner.py +4 -1
  9. minitap/mobile_use/agents/planner/types.py +3 -4
  10. minitap/mobile_use/agents/summarizer/summarizer.py +2 -1
  11. minitap/mobile_use/config.py +15 -15
  12. minitap/mobile_use/context.py +3 -4
  13. minitap/mobile_use/controllers/mobile_command_controller.py +32 -20
  14. minitap/mobile_use/controllers/platform_specific_commands_controller.py +3 -4
  15. minitap/mobile_use/graph/graph.py +1 -0
  16. minitap/mobile_use/graph/state.py +9 -9
  17. minitap/mobile_use/main.py +5 -6
  18. minitap/mobile_use/sdk/agent.py +24 -24
  19. minitap/mobile_use/sdk/builders/agent_config_builder.py +7 -8
  20. minitap/mobile_use/sdk/builders/task_request_builder.py +9 -9
  21. minitap/mobile_use/sdk/examples/smart_notification_assistant.py +1 -2
  22. minitap/mobile_use/sdk/types/agent.py +5 -5
  23. minitap/mobile_use/sdk/types/task.py +19 -18
  24. minitap/mobile_use/sdk/utils.py +1 -1
  25. minitap/mobile_use/servers/config.py +1 -2
  26. minitap/mobile_use/servers/device_hardware_bridge.py +3 -4
  27. minitap/mobile_use/servers/start_servers.py +4 -4
  28. minitap/mobile_use/servers/stop_servers.py +2 -3
  29. minitap/mobile_use/services/llm.py +3 -2
  30. minitap/mobile_use/tools/index.py +10 -4
  31. minitap/mobile_use/tools/mobile/back.py +1 -1
  32. minitap/mobile_use/tools/mobile/clear_text.py +277 -0
  33. minitap/mobile_use/tools/mobile/copy_text_from.py +1 -1
  34. minitap/mobile_use/tools/mobile/erase_one_char.py +56 -0
  35. minitap/mobile_use/tools/mobile/find_packages.py +1 -1
  36. minitap/mobile_use/tools/mobile/input_text.py +4 -80
  37. minitap/mobile_use/tools/mobile/launch_app.py +1 -1
  38. minitap/mobile_use/tools/mobile/long_press_on.py +2 -4
  39. minitap/mobile_use/tools/mobile/open_link.py +1 -1
  40. minitap/mobile_use/tools/mobile/paste_text.py +1 -1
  41. minitap/mobile_use/tools/mobile/press_key.py +1 -1
  42. minitap/mobile_use/tools/mobile/stop_app.py +2 -4
  43. minitap/mobile_use/tools/mobile/swipe.py +1 -1
  44. minitap/mobile_use/tools/mobile/take_screenshot.py +1 -1
  45. minitap/mobile_use/tools/mobile/tap.py +2 -4
  46. minitap/mobile_use/tools/mobile/wait_for_animation_to_end.py +2 -4
  47. minitap/mobile_use/tools/tool_wrapper.py +1 -1
  48. minitap/mobile_use/tools/utils.py +86 -0
  49. minitap/mobile_use/utils/cli_helpers.py +1 -2
  50. minitap/mobile_use/utils/cli_selection.py +5 -6
  51. minitap/mobile_use/utils/decorators.py +21 -20
  52. minitap/mobile_use/utils/logger.py +3 -4
  53. minitap/mobile_use/utils/media.py +1 -1
  54. minitap/mobile_use/utils/ui_hierarchy.py +13 -5
  55. {minitap_mobile_use-2.0.1.dist-info → minitap_mobile_use-2.1.0.dist-info}/METADATA +11 -1
  56. minitap_mobile_use-2.1.0.dist-info/RECORD +96 -0
  57. minitap/mobile_use/tools/mobile/erase_text.py +0 -122
  58. minitap_mobile_use-2.0.1.dist-info/RECORD +0 -94
  59. {minitap_mobile_use-2.0.1.dist-info → minitap_mobile_use-2.1.0.dist-info}/WHEEL +0 -0
  60. {minitap_mobile_use-2.0.1.dist-info → minitap_mobile_use-2.1.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,86 @@
1
+ from __future__ import annotations
2
+
3
+ from minitap.mobile_use.context import MobileUseContext
4
+ from minitap.mobile_use.controllers.mobile_command_controller import (
5
+ CoordinatesSelectorRequest,
6
+ IdSelectorRequest,
7
+ SelectorRequestWithCoordinates,
8
+ tap,
9
+ )
10
+ from minitap.mobile_use.graph.state import State
11
+ from minitap.mobile_use.utils.logger import get_logger
12
+ from minitap.mobile_use.utils.ui_hierarchy import (
13
+ Point,
14
+ find_element_by_resource_id,
15
+ get_bounds_for_element,
16
+ is_element_focused,
17
+ )
18
+
19
+ logger = get_logger(__name__)
20
+
21
+
22
+ def move_cursor_to_end_if_bounds(
23
+ ctx: MobileUseContext,
24
+ state: State,
25
+ resource_id: str,
26
+ elt: dict | None = None,
27
+ ) -> dict | None:
28
+ """
29
+ Best-effort move of the text cursor near the end of the input by tapping the
30
+ bottom-right area of the focused element (if bounds are available).
31
+ """
32
+ if not elt:
33
+ elt = find_element_by_resource_id(
34
+ ui_hierarchy=state.latest_ui_hierarchy or [],
35
+ resource_id=resource_id,
36
+ )
37
+ if not elt:
38
+ return
39
+
40
+ bounds = get_bounds_for_element(elt)
41
+ if not bounds:
42
+ return elt
43
+
44
+ logger.debug("Tapping near the end of the input to move the cursor")
45
+ bottom_right: Point = bounds.get_relative_point(x_percent=0.99, y_percent=0.99)
46
+ tap(
47
+ ctx=ctx,
48
+ selector_request=SelectorRequestWithCoordinates(
49
+ coordinates=CoordinatesSelectorRequest(
50
+ x=bottom_right.x,
51
+ y=bottom_right.y,
52
+ ),
53
+ ),
54
+ )
55
+ logger.debug(f"Tapped end of input {resource_id} at ({bottom_right.x}, {bottom_right.y})")
56
+ return elt
57
+
58
+
59
+ def focus_element_if_needed(
60
+ ctx: MobileUseContext,
61
+ resource_id: str,
62
+ ) -> bool:
63
+ """
64
+ Ensures the element identified by `resource_id` is focused.
65
+ """
66
+ rich_hierarchy: list[dict] = ctx.hw_bridge_client.get_rich_hierarchy()
67
+ rich_elt = find_element_by_resource_id(
68
+ ui_hierarchy=rich_hierarchy,
69
+ resource_id=resource_id,
70
+ is_rich_hierarchy=True,
71
+ )
72
+ if rich_elt and not is_element_focused(rich_elt):
73
+ tap(ctx=ctx, selector_request=IdSelectorRequest(id=resource_id))
74
+ logger.debug(f"Focused (tap) on resource_id={resource_id}")
75
+ rich_hierarchy = ctx.hw_bridge_client.get_rich_hierarchy()
76
+ rich_elt = find_element_by_resource_id(
77
+ ui_hierarchy=rich_hierarchy,
78
+ resource_id=resource_id,
79
+ is_rich_hierarchy=True,
80
+ )
81
+ if rich_elt and is_element_focused(rich_elt):
82
+ logger.debug(f"Text input is focused: {resource_id}")
83
+ return True
84
+
85
+ logger.warning(f"Failed to focus resource_id={resource_id}")
86
+ return False
@@ -3,10 +3,9 @@ import sys
3
3
  from minitap.mobile_use.clients.ios_client import get_ios_devices
4
4
  from adbutils import AdbClient
5
5
  from rich.console import Console
6
- from typing import Optional
7
6
 
8
7
 
9
- def display_device_status(console: Console, adb_client: Optional[AdbClient] = None):
8
+ def display_device_status(console: Console, adb_client: AdbClient | None = None):
10
9
  """Checks for connected devices and displays the status."""
11
10
  console.print("\n[bold]📱 Device Status[/bold]")
12
11
  devices = None
@@ -1,5 +1,4 @@
1
1
  import sys
2
- from typing import List, Optional
3
2
 
4
3
  import inquirer
5
4
  from rich.console import Console
@@ -8,12 +7,12 @@ from rich.prompt import Prompt
8
7
 
9
8
  def select_provider_and_model(
10
9
  console: Console,
11
- available_providers: List[str],
10
+ available_providers: list[str],
12
11
  available_models: dict,
13
12
  default_provider: str,
14
13
  default_model: str,
15
- provider: Optional[str] = None,
16
- model: Optional[str] = None,
14
+ provider: str | None = None,
15
+ model: str | None = None,
17
16
  ) -> tuple[str, str]:
18
17
  """
19
18
  Interactive selection of LLM provider and model with arrow-key dropdowns when available.
@@ -71,7 +70,7 @@ def select_provider_and_model(
71
70
  def _select_from_list(
72
71
  console: Console,
73
72
  item_type: str,
74
- choices: List[str],
73
+ choices: list[str],
75
74
  default: str,
76
75
  message: str,
77
76
  ) -> str:
@@ -108,7 +107,7 @@ def _select_from_list(
108
107
  return _numbered_selection(console, item_type, choices, default)
109
108
 
110
109
 
111
- def _numbered_selection(console: Console, item_type: str, choices: List[str], default: str) -> str:
110
+ def _numbered_selection(console: Console, item_type: str, choices: list[str], default: str) -> str:
112
111
  """Fallback numbered selection when arrow keys aren't available."""
113
112
  choices_text = "\n".join([f" {i + 1}. {choice}" for i, choice in enumerate(choices)])
114
113
  console.print(f"Available {item_type}s:\n{choices_text}")
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  from functools import wraps
3
- from typing import Any, Awaitable, Callable, Optional, TypeVar, cast, overload
3
+ from typing import Any, TypeVar, cast, overload
4
+ from collections.abc import Awaitable, Callable
4
5
 
5
6
  R = TypeVar("R")
6
7
 
@@ -8,9 +9,9 @@ R = TypeVar("R")
8
9
  def wrap_with_callbacks_sync(
9
10
  fn: Callable[..., R],
10
11
  *,
11
- before: Optional[Callable[..., None]] = None,
12
- on_success: Optional[Callable[[R], None]] = None,
13
- on_failure: Optional[Callable[[Exception], None]] = None,
12
+ before: Callable[..., None] | None = None,
13
+ on_success: Callable[[R], None] | None = None,
14
+ on_failure: Callable[[Exception], None] | None = None,
14
15
  suppress_exceptions: bool = False,
15
16
  ) -> Callable[..., R]:
16
17
  @wraps(fn)
@@ -35,9 +36,9 @@ def wrap_with_callbacks_sync(
35
36
  def wrap_with_callbacks_async(
36
37
  fn: Callable[..., Awaitable[R]],
37
38
  *,
38
- before: Optional[Callable[..., None]] = None,
39
- on_success: Optional[Callable[[R], None]] = None,
40
- on_failure: Optional[Callable[[Exception], None]] = None,
39
+ before: Callable[..., None] | None = None,
40
+ on_success: Callable[[R], None] | None = None,
41
+ on_failure: Callable[[Exception], None] | None = None,
41
42
  suppress_exceptions: bool = False,
42
43
  ) -> Callable[..., Awaitable[R]]:
43
44
  @wraps(fn)
@@ -63,9 +64,9 @@ def wrap_with_callbacks_async(
63
64
  def wrap_with_callbacks(
64
65
  fn: Callable[..., Awaitable[R]],
65
66
  *,
66
- before: Optional[Callable[[], None]] = ...,
67
- on_success: Optional[Callable[[R], None]] = ...,
68
- on_failure: Optional[Callable[[Exception], None]] = ...,
67
+ before: Callable[[], None] | None = ...,
68
+ on_success: Callable[[R], None] | None = ...,
69
+ on_failure: Callable[[Exception], None] | None = ...,
69
70
  suppress_exceptions: bool = ...,
70
71
  ) -> Callable[..., Awaitable[R]]: ...
71
72
 
@@ -73,9 +74,9 @@ def wrap_with_callbacks(
73
74
  @overload
74
75
  def wrap_with_callbacks(
75
76
  *,
76
- before: Optional[Callable[..., None]] = ...,
77
- on_success: Optional[Callable[[Any], None]] = ...,
78
- on_failure: Optional[Callable[[Exception], None]] = ...,
77
+ before: Callable[..., None] | None = ...,
78
+ on_success: Callable[[Any], None] | None = ...,
79
+ on_failure: Callable[[Exception], None] | None = ...,
79
80
  suppress_exceptions: bool = ...,
80
81
  ) -> Callable[[Callable[..., R]], Callable[..., R]]: ...
81
82
 
@@ -84,19 +85,19 @@ def wrap_with_callbacks(
84
85
  def wrap_with_callbacks(
85
86
  fn: Callable[..., R],
86
87
  *,
87
- before: Optional[Callable[[], None]] = ...,
88
- on_success: Optional[Callable[[R], None]] = ...,
89
- on_failure: Optional[Callable[[Exception], None]] = ...,
88
+ before: Callable[[], None] | None = ...,
89
+ on_success: Callable[[R], None] | None = ...,
90
+ on_failure: Callable[[Exception], None] | None = ...,
90
91
  suppress_exceptions: bool = ...,
91
92
  ) -> Callable[..., R]: ...
92
93
 
93
94
 
94
95
  def wrap_with_callbacks(
95
- fn: Optional[Callable[..., Any]] = None,
96
+ fn: Callable[..., Any] | None = None,
96
97
  *,
97
- before: Optional[Callable[[], None]] = None,
98
- on_success: Optional[Callable[[Any], None]] = None,
99
- on_failure: Optional[Callable[[Exception], None]] = None,
98
+ before: Callable[[], None] | None = None,
99
+ on_success: Callable[[Any], None] | None = None,
100
+ on_failure: Callable[[Exception], None] | None = None,
100
101
  suppress_exceptions: bool = False,
101
102
  ) -> Any:
102
103
  def decorator(func: Callable[..., Any]) -> Any:
@@ -2,7 +2,6 @@ import logging
2
2
  import sys
3
3
  from enum import Enum
4
4
  from pathlib import Path
5
- from typing import Optional, Union
6
5
 
7
6
  from colorama import Fore, Style, init
8
7
 
@@ -22,7 +21,7 @@ class MobileUseLogger:
22
21
  def __init__(
23
22
  self,
24
23
  name: str,
25
- log_file: Optional[Union[str, Path]] = None,
24
+ log_file: str | Path | None = None,
26
25
  console_level: str = "INFO",
27
26
  file_level: str = "DEBUG",
28
27
  enable_file_logging: bool = True,
@@ -57,7 +56,7 @@ class MobileUseLogger:
57
56
 
58
57
  self.logger.addHandler(console_handler)
59
58
 
60
- def _setup_file_handler(self, log_file: Optional[Union[str, Path]], level: str):
59
+ def _setup_file_handler(self, log_file: str | Path | None, level: str):
61
60
  if log_file is None:
62
61
  log_file = Path("logs") / f"{self.name.replace('.', '_')}.log"
63
62
 
@@ -118,7 +117,7 @@ _loggers = {}
118
117
 
119
118
  def get_logger(
120
119
  name: str,
121
- log_file: Optional[Union[str, Path]] = None,
120
+ log_file: str | Path | None = None,
122
121
  console_level: str = "INFO",
123
122
  file_level: str = "DEBUG",
124
123
  enable_file_logging: bool = False,
@@ -55,7 +55,7 @@ def create_steps_json_from_trace_folder(trace_folder_path: Path):
55
55
  steps = []
56
56
  for file in trace_folder_path.iterdir():
57
57
  if file.suffix == ".json":
58
- with open(file, "r", encoding="utf-8", errors="ignore") as f:
58
+ with open(file, encoding="utf-8", errors="ignore") as f:
59
59
  json_content = f.read()
60
60
  steps.append({"timestamp": int(file.stem), "data": json_content})
61
61
 
@@ -1,5 +1,3 @@
1
- from typing import Optional
2
-
3
1
  from pydantic import BaseModel
4
2
 
5
3
  from minitap.mobile_use.utils.logger import get_logger
@@ -9,7 +7,7 @@ logger = get_logger(__name__)
9
7
 
10
8
  def __find_element_by_ressource_id_in_rich_hierarchy(
11
9
  hierarchy: list[dict], resource_id: str
12
- ) -> Optional[dict]:
10
+ ) -> dict | None:
13
11
  """
14
12
  Retrieves all the sibling elements for a given resource ID from a nested dictionary.
15
13
 
@@ -37,9 +35,13 @@ def __find_element_by_ressource_id_in_rich_hierarchy(
37
35
  return None
38
36
 
39
37
 
38
+ def text_input_is_empty(text: str | None, hint_text: str | None) -> bool:
39
+ return not text or text == hint_text
40
+
41
+
40
42
  def find_element_by_resource_id(
41
43
  ui_hierarchy: list[dict], resource_id: str, is_rich_hierarchy: bool = False
42
- ) -> Optional[dict]:
44
+ ) -> dict | None:
43
45
  """
44
46
  Find a UI element by its resource-id in the UI hierarchy.
45
47
 
@@ -54,7 +56,7 @@ def find_element_by_resource_id(
54
56
  if is_rich_hierarchy:
55
57
  return __find_element_by_ressource_id_in_rich_hierarchy(ui_hierarchy, resource_id)
56
58
 
57
- def search_recursive(elements: list[dict]) -> Optional[dict]:
59
+ def search_recursive(elements: list[dict]) -> dict | None:
58
60
  for element in elements:
59
61
  if isinstance(element, dict):
60
62
  if element.get("resourceId") == resource_id:
@@ -74,6 +76,12 @@ def is_element_focused(element: dict) -> bool:
74
76
  return element.get("focused", None) == "true"
75
77
 
76
78
 
79
+ def get_element_text(element: dict, hint_text: bool = False) -> str | None:
80
+ if hint_text:
81
+ return element.get("hintText", None)
82
+ return element.get("text", None)
83
+
84
+
77
85
  class Point(BaseModel):
78
86
  x: int
79
87
  y: int
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: minitap-mobile-use
3
- Version: 2.0.1
3
+ Version: 2.1.0
4
4
  Summary: AI-powered multi-agent system that automates real Android and iOS devices through low-level control using LangGraph.
5
5
  Author: Pierre-Louis Favreau, Jean-Pierre Lo, Nicolas Dehandschoewercker
6
6
  License: MIT License
@@ -257,6 +257,16 @@ python ./src/mobile_use/main.py \
257
257
  > [!NOTE]
258
258
  > If you haven't configured a specific model, mobile-use will prompt you to choose one from the available options.
259
259
 
260
+ ## 🔎 Agentic System Overview
261
+
262
+ <div align="center">
263
+
264
+ ![Graph Visualization](doc/graph.png)
265
+
266
+ _This diagram is automatically updated from the codebase. This is our current agentic system architecture._
267
+
268
+ </div>
269
+
260
270
  ## ❤️ Contributing
261
271
 
262
272
  We love contributions! Whether you're fixing a bug, adding a feature, or improving documentation, your help is welcome. Please read our **[Contributing Guidelines](CONTRIBUTING.md)** to get started.
@@ -0,0 +1,96 @@
1
+ minitap/mobile_use/__init__.py,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
2
+ minitap/mobile_use/agents/contextor/contextor.py,sha256=d7c98771a9173281c1660a2ee965149d4f70ecf7005cf75fa89eb1e9a9f2b660,1673
3
+ minitap/mobile_use/agents/cortex/cortex.md,sha256=69358852474f65144486fc60196b17bdc5f99d2891fbb4cae26fd2331260f6ba,5598
4
+ minitap/mobile_use/agents/cortex/cortex.py,sha256=232dfe2e2dbbfbc34873875ee32cf5f9d4156f6b9afc9d9d9146addd102be40c,4896
5
+ minitap/mobile_use/agents/cortex/types.py,sha256=c33f2277752644d2185d84add03a493adaa530096d046d73366ab9121d99b946,361
6
+ minitap/mobile_use/agents/executor/executor.md,sha256=800003af904d346ab0a6b8a205c0332930161a8c997ede584097a40e8f1ac478,2806
7
+ minitap/mobile_use/agents/executor/executor.py,sha256=be92742d91296650288c12e83f8065589d8eab7aeaa977a47c34ed25879a9bb6,2771
8
+ minitap/mobile_use/agents/executor/tool_node.py,sha256=2ad729ede393882460ae3d180ac1c0e1ab1688f40b2017220aad1b059f6485c5,3900
9
+ minitap/mobile_use/agents/executor/utils.py,sha256=1a387d30047d3be05b5e550433866abe4388222b3f95d1360847870155ef8f12,368
10
+ minitap/mobile_use/agents/hopper/hopper.md,sha256=2e9333ece8f6b76401ac2cce98ca06a025faa5dba6bacbbc344793ddf42292d0,362
11
+ minitap/mobile_use/agents/hopper/hopper.py,sha256=1c015cc911f225c9cb26415e0852d5905ded8e715fb928ad2595143870a781e3,1324
12
+ minitap/mobile_use/agents/orchestrator/human.md,sha256=6559026aa921b7ad7dddcf3dfcd5d9930252edd6484d60ea92ff6ca97ed028fc,229
13
+ minitap/mobile_use/agents/orchestrator/orchestrator.md,sha256=cc1a353c577f2eef42d9a528178ccc2c0a4a144a907a29878f9efe57e83b12fa,2546
14
+ minitap/mobile_use/agents/orchestrator/orchestrator.py,sha256=83524eefe8fc1d9639a2ffeb270dfed9e2a2b15af93e6e1d3d41d8e7c5b74951,4656
15
+ minitap/mobile_use/agents/orchestrator/types.py,sha256=f53dfdc99e8d50888ac1cde5f7f90ba5c87837a8eee8dd8efa31f2640394433c,335
16
+ minitap/mobile_use/agents/outputter/human.md,sha256=6b9b45c640b163554524b1aec4cd97134c628eeb8557a32e23c8f966d32f642e,771
17
+ minitap/mobile_use/agents/outputter/outputter.py,sha256=0539cd1bfa307c6e24136488a0481128da17c37f20128e63388b5c4aea5aae50,2750
18
+ minitap/mobile_use/agents/outputter/test_outputter.py,sha256=4c52988f8f29159657707a0e11500610f3987cac6390b17edec23f09ddfcc0ff,3334
19
+ minitap/mobile_use/agents/planner/human.md,sha256=cb37be2af568918e60238eaa785837178a3ba8f8112de86850d9a62914c18314,222
20
+ minitap/mobile_use/agents/planner/planner.md,sha256=41c973c8d34a6c24c81b275f725fc447d58805dcea1900f4285c5980502fc756,3337
21
+ minitap/mobile_use/agents/planner/planner.py,sha256=0b8c92857847d390d98efb8d1130762883e46ea4dfc354ea3352e45450913771,2686
22
+ minitap/mobile_use/agents/planner/types.py,sha256=da551df70ae4ae574670bd8d79c4da1a82be88c24216034d6841a83d85c0c43c,1392
23
+ minitap/mobile_use/agents/planner/utils.py,sha256=11731d0382bf88ef77b38aaf75873486f293343cdd048372c57e626c652b4a22,1839
24
+ minitap/mobile_use/agents/summarizer/summarizer.py,sha256=3e1e92f9259c040487992636786f972dffe0a38d309a8c3758c9ff1aeff2f62c,1070
25
+ minitap/mobile_use/clients/device_hardware_client.py,sha256=9593380a7a3df32f02aa22717678c25e91367df26b1743abde9e57aec5dc2474,857
26
+ minitap/mobile_use/clients/ios_client.py,sha256=332bf47ac01bbd5bf6178a59eea7c7a30fed944f30907caea5388178f312d36b,1452
27
+ minitap/mobile_use/clients/screen_api_client.py,sha256=3615dc65d25c38b4d8dc5512f9adb3bcf69dca7a0298a472a6812f604a275c47,2019
28
+ minitap/mobile_use/config.py,sha256=d5bd2bf71f229d57757bf8375b5caf858b4964178507ecb855942bb197646fdd,9399
29
+ minitap/mobile_use/constants.py,sha256=3acd9d6ade5bc772e902b3473f3ba12ddd04e7306963ca2bae49d1132d89ba46,95
30
+ minitap/mobile_use/context.py,sha256=fa4e43fb580db86c2ed707b1464d8363ead57332b40ea5688e0731ad57a40558,1747
31
+ minitap/mobile_use/controllers/__init__.py,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
32
+ minitap/mobile_use/controllers/mobile_command_controller.py,sha256=1ea22f569affae3d82ea74afd37629898cf3d10b3bdf6cb1a7671d1a09f2c000,12206
33
+ minitap/mobile_use/controllers/platform_specific_commands_controller.py,sha256=8b4fc30108c242da41fd998751dbfd5e6a69e2957a2dbbe5d6fc43d6b55f727e,2705
34
+ minitap/mobile_use/graph/graph.py,sha256=c7b412e725b096eca8f212d704c3faf91d77eea4131f1fae7af1ee39bc57cdae,4269
35
+ minitap/mobile_use/graph/state.py,sha256=cfe67d15833efa18b28a86293bc5c713ff8c777778b0552bb6e25fa7070534aa,3371
36
+ minitap/mobile_use/main.py,sha256=51a826974071997d7ca1d6913e199c7844633e483db0471f3c294688be028834,3743
37
+ minitap/mobile_use/sdk/__init__.py,sha256=4e5555c0597242b9523827194a2500b9c6d7e5c04b1ccd2056c9b1f4d42a31cd,318
38
+ minitap/mobile_use/sdk/agent.py,sha256=43b198cfabdffa28add7f1b77046704ee28da74da92b710dc8bb265c8df16472,20898
39
+ minitap/mobile_use/sdk/builders/__init__.py,sha256=d6c96d39b80900a114698ef205ab5061a541f33bfa99c456d9345e5adb8ff6ff,424
40
+ minitap/mobile_use/sdk/builders/agent_config_builder.py,sha256=d963ab932fa78117eef3ea4a2503c34b872f7b865c1a2e25b20e7fa5072e466b,7600
41
+ minitap/mobile_use/sdk/builders/index.py,sha256=64336ac3b3dea4673a48e95b8c5ac4196ecd5d2196380377d102593d0a1dc138,442
42
+ minitap/mobile_use/sdk/builders/task_request_builder.py,sha256=9e6cf7afb68af986d6a81487179bb79d28f63047a068725d92996dbcbe753376,6857
43
+ minitap/mobile_use/sdk/constants.py,sha256=436ba0700c6cf37ac0c9e3995a5f5a0d54ca87af72686eb9667a2c6a96e30f68,292
44
+ minitap/mobile_use/sdk/examples/README.md,sha256=b6780de3025b1897ad2ef42fa968f2a69b82f929465807f9590c4e9321dab6e6,2306
45
+ minitap/mobile_use/sdk/examples/__init__.py,sha256=c23868a2ca7e9b76e80d6835fe93c10e13ea8f2287dd6e785511b8ac30354e9b,46
46
+ minitap/mobile_use/sdk/examples/simple_photo_organizer.py,sha256=8ad1cebb5281e3663264560bd15b090add41d2821b1db77e4cbc829860c98df8,2606
47
+ minitap/mobile_use/sdk/examples/smart_notification_assistant.py,sha256=1d00658dc30c7bce5ef68369f982cd2d1932f53e2e2da6ded70cea13dc669c72,6362
48
+ minitap/mobile_use/sdk/types/__init__.py,sha256=5dd148d83bf6261ac8ac60c994e2496b5bf535591d0835807d5fe394fd85a954,1014
49
+ minitap/mobile_use/sdk/types/agent.py,sha256=390d5c642b3480f4a2203ddd28ec115c785f2576bec81e82e4db3c129399c020,2260
50
+ minitap/mobile_use/sdk/types/exceptions.py,sha256=56ac3f749730740951448b1b0f200be21331dc0800916a87587b21e7850120a5,2288
51
+ minitap/mobile_use/sdk/types/task.py,sha256=74743a398b63af62383528d5906824ae8aaba1e1885c75414b347623d7931f12,5837
52
+ minitap/mobile_use/sdk/utils.py,sha256=493c77e43fcb58535eef43416716a3283488577c127060de5c0317d0b737b01f,945
53
+ minitap/mobile_use/servers/config.py,sha256=8a4a6bce23e2093d047a91e135e2f88627f76ac12177d071f25a3ca739b3afeb,575
54
+ minitap/mobile_use/servers/device_hardware_bridge.py,sha256=80b93fe1bd8ea9100ac198a83f0aea2c40565a11e810acff9785bbd3f3b31f37,7174
55
+ minitap/mobile_use/servers/device_screen_api.py,sha256=63bf866f17cde4ab97631b710080866b8427225d3857b2351ab83db38a9c5107,5064
56
+ minitap/mobile_use/servers/start_servers.py,sha256=1e86dc0fcbdf6e6570ae68c7097145e754f3c3448ca813d415b3e5ebb74db828,5037
57
+ minitap/mobile_use/servers/stop_servers.py,sha256=9a3dc2eafb3c13e420248b1844694c80112be32f0d336f54ecc1015cb6f27be9,7127
58
+ minitap/mobile_use/servers/utils.py,sha256=db5d26153a169ab141556337db3693adc1bf8522943316656bdeb05dbf95465b,394
59
+ minitap/mobile_use/services/accessibility.py,sha256=42bcbe81b427ee6f6e82bcfe420fc40630db950bda354e3e433c2dda2e159628,3404
60
+ minitap/mobile_use/services/llm.py,sha256=c3e99290431bcdcbf81cbffd08bf3abbd4a3760c20cb0873278c418df0d28b0f,3724
61
+ minitap/mobile_use/tools/index.py,sha256=db61053f24beb88952cc34be37336defd8ebf5e1fec0ecf81e2439a76b29bde1,2449
62
+ minitap/mobile_use/tools/mobile/back.py,sha256=cf1053b22c4fbeb1c219578563d6d857425dcdff08af690149c6e52a0e29c195,1792
63
+ minitap/mobile_use/tools/mobile/clear_text.py,sha256=28e9af14cbb62be3a8221e7b1e7645e9bc22f40202d84c6047874809137cd927,9316
64
+ minitap/mobile_use/tools/mobile/copy_text_from.py,sha256=723d7563e19d05060da0071aedfb620ce36bfb90931fcb815ab8d01be7ed9dd5,2716
65
+ minitap/mobile_use/tools/mobile/erase_one_char.py,sha256=e8c0a519a235271fa1cb785fe711e63e9ca14f4d33a61fbb39af04ec9bf18211,1960
66
+ minitap/mobile_use/tools/mobile/find_packages.py,sha256=78f3051f40307ba75655fbffe6fe3fc3954f158eb8ceb0d270cb81a5e807d81d,2554
67
+ minitap/mobile_use/tools/mobile/input_text.py,sha256=6a0b48ac79ad908fd6229a63fe17f7c5f26fb0e7466632700efd5db40393bda5,3199
68
+ minitap/mobile_use/tools/mobile/launch_app.py,sha256=e1879333c0eae92b22ec3c147edd26dfe41252bf8049e5954a0b72d5a8b8f650,2027
69
+ minitap/mobile_use/tools/mobile/long_press_on.py,sha256=b59bf885a10e7468069e5523eb7d23bfa6d41efc7d0521f7622e4dd2260fe879,2194
70
+ minitap/mobile_use/tools/mobile/open_link.py,sha256=ad363f83b254a8e3e5969b4d8b90ef4e1fc4eceacc9c976e02a3e110e80ad23f,1875
71
+ minitap/mobile_use/tools/mobile/paste_text.py,sha256=dc126297f174cdcdfc6f6d148fdb6a96ecb7813926e441ce0631e963b196b448,2101
72
+ minitap/mobile_use/tools/mobile/press_key.py,sha256=a22d416279c33f2e843aaf28e4466a7eeae59aa690312c8866b62a3f84b57d5b,1939
73
+ minitap/mobile_use/tools/mobile/stop_app.py,sha256=8fc1cf5682232d670270a7e909f365a795150643eac5310f042d792b79e7c0c0,2062
74
+ minitap/mobile_use/tools/mobile/swipe.py,sha256=4d0da8c0db0995598a9a74ebfc5e7fdc176abc8e5277fd8d5f588de864947dda,1878
75
+ minitap/mobile_use/tools/mobile/take_screenshot.py,sha256=8762be82e0fb55549f1271a8e4c7b25040f906d21ed19f52121a616e70eb9bb0,2271
76
+ minitap/mobile_use/tools/mobile/tap.py,sha256=d7a3de2ddb78b051b22d7886553d75bab13562abfc8562957c15fb16dd484a0a,2297
77
+ minitap/mobile_use/tools/mobile/wait_for_animation_to_end.py,sha256=967d0df11dfb073dde6308761e9795e02c93ee2b0cbe17caf6edbe4a8beea28a,2493
78
+ minitap/mobile_use/tools/tool_wrapper.py,sha256=166d9c4b7950e66407eb397a81d88354779ee3056a8dc7ad1bf160a3aa54580c,334
79
+ minitap/mobile_use/tools/utils.py,sha256=bf6924e3d9e5338c2e04d88fd0ad9ed03a0c02058b62373025fa4b3a805712ae,2694
80
+ minitap/mobile_use/utils/cli_helpers.py,sha256=1c53b6ea6cd2ba861302b182944c6a3a31dac27e316bca2c65cd6a3ca3256e81,1720
81
+ minitap/mobile_use/utils/cli_selection.py,sha256=62e949bf075e984b5d23b4a9880ff2bccf8f9e0f7ccb48120030a6a82075352b,4788
82
+ minitap/mobile_use/utils/conversations.py,sha256=8f1d924300ec3f6f7c71510c21e3011b75caca5b1fff06fdaccb377c3cde24ec,914
83
+ minitap/mobile_use/utils/decorators.py,sha256=0bb30fb4f5d5cef0aef45643e68e199d39910f1d771eb4086f3e083d566c16a5,3591
84
+ minitap/mobile_use/utils/errors.py,sha256=6c5566484cff48ce1eb168c3cbe93d6e5365457828f59616a15147598feef769,156
85
+ minitap/mobile_use/utils/file.py,sha256=1ca968613452a273b23e4f58460ab39f87255b02cdb6fb8ca04f4e628b346070,315
86
+ minitap/mobile_use/utils/logger.py,sha256=011fe08c39b111997ec685b9f0b378761607e35ac049234b5e86c2b58f29bbe3,5633
87
+ minitap/mobile_use/utils/media.py,sha256=29fa7f009a0f2bd60de2a9eba4a90e6eecc91cc67c2736b753506d48ab2bf5eb,2228
88
+ minitap/mobile_use/utils/recorder.py,sha256=83dcb953b9caf00bf3e4853c3eee447166e1279e7ceefbbeb25d93e932ec698d,1937
89
+ minitap/mobile_use/utils/requests_utils.py,sha256=5c3a2e2aff7c521cd6a43b74c084e2244e1ff55065a5b722e6e251c6419861fd,1168
90
+ minitap/mobile_use/utils/shell_utils.py,sha256=b35ae7f863379adb86c9ba0f9b3b9d4954118d12aef1ffed0bc260b32d73d857,650
91
+ minitap/mobile_use/utils/time.py,sha256=41bfaabb3751de11443ccb4a3f1f53d5ebacc7744c72e32695fdcc3d23f17d49,160
92
+ minitap/mobile_use/utils/ui_hierarchy.py,sha256=b52acd081ac18169dab94b7187c6ffed4db72d4e4b7f56aeca9ef5b81166c4e0,3630
93
+ minitap_mobile_use-2.1.0.dist-info/WHEEL,sha256=ab6157bc637547491fb4567cd7ddf26b04d63382916ca16c29a5c8e94c9c9ef7,79
94
+ minitap_mobile_use-2.1.0.dist-info/entry_points.txt,sha256=663a29cfd551a4eaa0f27335f0bd7e4a732a4e39c76b68ef5c8dc444d4a285fa,60
95
+ minitap_mobile_use-2.1.0.dist-info/METADATA,sha256=95abc6db29ea323284374508c8faba3fd6cf83db998a2a45b82585af354b8ab2,10574
96
+ minitap_mobile_use-2.1.0.dist-info/RECORD,,
@@ -1,122 +0,0 @@
1
- from typing import Optional
2
-
3
- from langchain_core.messages import ToolMessage
4
- from langchain_core.tools import tool
5
- from langchain_core.tools.base import InjectedToolCallId
6
- from langgraph.prebuilt import InjectedState
7
- from langgraph.types import Command
8
- from typing_extensions import Annotated
9
-
10
- from minitap.mobile_use.constants import EXECUTOR_MESSAGES_KEY
11
- from minitap.mobile_use.controllers.mobile_command_controller import (
12
- ScreenDataResponse,
13
- WaitTimeout,
14
- get_screen_data,
15
- wait_for_animation_to_end,
16
- )
17
- from minitap.mobile_use.controllers.mobile_command_controller import (
18
- erase_text as erase_text_controller,
19
- )
20
- from minitap.mobile_use.graph.state import State
21
- from minitap.mobile_use.tools.tool_wrapper import ToolWrapper
22
- from minitap.mobile_use.utils.ui_hierarchy import find_element_by_resource_id
23
- from minitap.mobile_use.context import MobileUseContext
24
-
25
-
26
- def get_erase_text_tool(ctx: MobileUseContext):
27
- @tool
28
- def erase_text(
29
- tool_call_id: Annotated[str, InjectedToolCallId],
30
- state: Annotated[State, InjectedState],
31
- agent_thought: str,
32
- input_text_resource_id: str,
33
- nb_chars: Optional[int] = None,
34
- ):
35
- """
36
- Erases up to `nb_chars` characters from the currently selected text field (default: 50).
37
-
38
- iOS Note:
39
- This may be flaky on iOS. As a workaround:
40
- - long_press_on("<input id>")
41
- - tap_on("Select All")
42
- - erase_text()
43
-
44
- Matches 'clearText' in search.
45
- """
46
- # value of text key from input_text_ressource_id
47
- latest_ui_hierarchy = state.latest_ui_hierarchy
48
- previous_text_value = None
49
- new_text_value = None
50
- nb_char_erased = -1
51
- if latest_ui_hierarchy is not None:
52
- text_input_element = find_element_by_resource_id(
53
- ui_hierarchy=latest_ui_hierarchy, resource_id=input_text_resource_id
54
- )
55
- if text_input_element:
56
- previous_text_value = text_input_element.get("text", None)
57
-
58
- output = erase_text_controller(ctx=ctx, nb_chars=nb_chars)
59
- has_failed = output is not None
60
-
61
- wait_for_animation_to_end(ctx=ctx, timeout=WaitTimeout.MEDIUM)
62
-
63
- screen_data: ScreenDataResponse = get_screen_data(screen_api_client=ctx.screen_api_client)
64
- latest_ui_hierarchy = screen_data.elements
65
-
66
- if not has_failed and latest_ui_hierarchy is not None:
67
- text_input_element = find_element_by_resource_id(
68
- ui_hierarchy=latest_ui_hierarchy, resource_id=input_text_resource_id
69
- )
70
- if text_input_element:
71
- new_text_value = text_input_element.get("text", None)
72
-
73
- if previous_text_value is not None and new_text_value is not None:
74
- if previous_text_value == new_text_value:
75
- has_failed = True
76
- output = (
77
- "Unable to erase text: text is very likely a placeholder."
78
- " Thus, assuming the text input is empty."
79
- )
80
- else:
81
- nb_char_erased = len(previous_text_value) - len(new_text_value)
82
- tool_message = ToolMessage(
83
- tool_call_id=tool_call_id,
84
- content=erase_text_wrapper.on_failure_fn(output)
85
- if has_failed
86
- else erase_text_wrapper.on_success_fn(
87
- nb_char_erased=nb_char_erased, new_text_value=new_text_value
88
- ),
89
- additional_kwargs={"error": output} if has_failed else {},
90
- status="error" if has_failed else "success",
91
- )
92
-
93
- return Command(
94
- update=state.sanitize_update(
95
- ctx=ctx,
96
- update={
97
- "agents_thoughts": [agent_thought],
98
- EXECUTOR_MESSAGES_KEY: [tool_message],
99
- },
100
- agent="executor",
101
- ),
102
- )
103
-
104
- return erase_text
105
-
106
-
107
- def format_success_message(nb_char_erased: int, new_text_value: Optional[str]):
108
- output = ""
109
- if nb_char_erased == -1:
110
- output = "Text erased successfully."
111
- else:
112
- output = f"Text erased successfully. {nb_char_erased} characters were erased."
113
- if new_text_value is not None:
114
- output += f" New text in the input is {new_text_value}."
115
- return output
116
-
117
-
118
- erase_text_wrapper = ToolWrapper(
119
- tool_fn_getter=get_erase_text_tool,
120
- on_success_fn=format_success_message,
121
- on_failure_fn=lambda output: "Failed to erase text. " + output,
122
- )