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.
- minitap/mobile_use/agents/cortex/cortex.md +7 -5
- minitap/mobile_use/agents/cortex/cortex.py +4 -1
- minitap/mobile_use/agents/cortex/types.py +1 -3
- minitap/mobile_use/agents/executor/executor.md +4 -5
- minitap/mobile_use/agents/executor/tool_node.py +6 -6
- minitap/mobile_use/agents/outputter/outputter.py +1 -2
- minitap/mobile_use/agents/planner/planner.md +11 -2
- minitap/mobile_use/agents/planner/planner.py +4 -1
- minitap/mobile_use/agents/planner/types.py +3 -4
- minitap/mobile_use/agents/summarizer/summarizer.py +2 -1
- minitap/mobile_use/config.py +15 -15
- minitap/mobile_use/context.py +3 -4
- minitap/mobile_use/controllers/mobile_command_controller.py +32 -20
- minitap/mobile_use/controllers/platform_specific_commands_controller.py +3 -4
- minitap/mobile_use/graph/graph.py +1 -0
- minitap/mobile_use/graph/state.py +9 -9
- minitap/mobile_use/main.py +5 -6
- minitap/mobile_use/sdk/agent.py +24 -24
- minitap/mobile_use/sdk/builders/agent_config_builder.py +7 -8
- minitap/mobile_use/sdk/builders/task_request_builder.py +9 -9
- minitap/mobile_use/sdk/examples/smart_notification_assistant.py +1 -2
- minitap/mobile_use/sdk/types/agent.py +5 -5
- minitap/mobile_use/sdk/types/task.py +19 -18
- minitap/mobile_use/sdk/utils.py +1 -1
- minitap/mobile_use/servers/config.py +1 -2
- minitap/mobile_use/servers/device_hardware_bridge.py +3 -4
- minitap/mobile_use/servers/start_servers.py +4 -4
- minitap/mobile_use/servers/stop_servers.py +2 -3
- minitap/mobile_use/services/llm.py +3 -2
- minitap/mobile_use/tools/index.py +10 -4
- minitap/mobile_use/tools/mobile/back.py +1 -1
- minitap/mobile_use/tools/mobile/clear_text.py +277 -0
- minitap/mobile_use/tools/mobile/copy_text_from.py +1 -1
- minitap/mobile_use/tools/mobile/erase_one_char.py +56 -0
- minitap/mobile_use/tools/mobile/find_packages.py +1 -1
- minitap/mobile_use/tools/mobile/input_text.py +4 -80
- minitap/mobile_use/tools/mobile/launch_app.py +1 -1
- minitap/mobile_use/tools/mobile/long_press_on.py +2 -4
- minitap/mobile_use/tools/mobile/open_link.py +1 -1
- minitap/mobile_use/tools/mobile/paste_text.py +1 -1
- minitap/mobile_use/tools/mobile/press_key.py +1 -1
- minitap/mobile_use/tools/mobile/stop_app.py +2 -4
- minitap/mobile_use/tools/mobile/swipe.py +1 -1
- minitap/mobile_use/tools/mobile/take_screenshot.py +1 -1
- minitap/mobile_use/tools/mobile/tap.py +2 -4
- minitap/mobile_use/tools/mobile/wait_for_animation_to_end.py +2 -4
- minitap/mobile_use/tools/tool_wrapper.py +1 -1
- minitap/mobile_use/tools/utils.py +86 -0
- minitap/mobile_use/utils/cli_helpers.py +1 -2
- minitap/mobile_use/utils/cli_selection.py +5 -6
- minitap/mobile_use/utils/decorators.py +21 -20
- minitap/mobile_use/utils/logger.py +3 -4
- minitap/mobile_use/utils/media.py +1 -1
- minitap/mobile_use/utils/ui_hierarchy.py +13 -5
- {minitap_mobile_use-2.0.1.dist-info → minitap_mobile_use-2.1.0.dist-info}/METADATA +11 -1
- minitap_mobile_use-2.1.0.dist-info/RECORD +96 -0
- minitap/mobile_use/tools/mobile/erase_text.py +0 -122
- minitap_mobile_use-2.0.1.dist-info/RECORD +0 -94
- {minitap_mobile_use-2.0.1.dist-info → minitap_mobile_use-2.1.0.dist-info}/WHEEL +0 -0
- {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:
|
|
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:
|
|
10
|
+
available_providers: list[str],
|
|
12
11
|
available_models: dict,
|
|
13
12
|
default_provider: str,
|
|
14
13
|
default_model: str,
|
|
15
|
-
provider:
|
|
16
|
-
model:
|
|
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:
|
|
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:
|
|
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,
|
|
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:
|
|
12
|
-
on_success:
|
|
13
|
-
on_failure:
|
|
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:
|
|
39
|
-
on_success:
|
|
40
|
-
on_failure:
|
|
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:
|
|
67
|
-
on_success:
|
|
68
|
-
on_failure:
|
|
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:
|
|
77
|
-
on_success:
|
|
78
|
-
on_failure:
|
|
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:
|
|
88
|
-
on_success:
|
|
89
|
-
on_failure:
|
|
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:
|
|
96
|
+
fn: Callable[..., Any] | None = None,
|
|
96
97
|
*,
|
|
97
|
-
before:
|
|
98
|
-
on_success:
|
|
99
|
-
on_failure:
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
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
|
-
) ->
|
|
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
|
-
) ->
|
|
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]) ->
|
|
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
|
|
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
|
+

|
|
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
|
-
)
|