autoglm-gui 1.4.1__py3-none-any.whl → 1.5.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.
- AutoGLM_GUI/__init__.py +11 -0
- AutoGLM_GUI/__main__.py +26 -4
- AutoGLM_GUI/actions/__init__.py +6 -0
- AutoGLM_GUI/actions/handler.py +196 -0
- AutoGLM_GUI/actions/types.py +15 -0
- AutoGLM_GUI/adb/__init__.py +53 -0
- AutoGLM_GUI/adb/apps.py +227 -0
- AutoGLM_GUI/adb/connection.py +323 -0
- AutoGLM_GUI/adb/device.py +171 -0
- AutoGLM_GUI/adb/input.py +67 -0
- AutoGLM_GUI/adb/screenshot.py +11 -0
- AutoGLM_GUI/adb/timing.py +167 -0
- AutoGLM_GUI/adb_plus/keyboard_installer.py +4 -2
- AutoGLM_GUI/adb_plus/screenshot.py +22 -1
- AutoGLM_GUI/adb_plus/serial.py +38 -20
- AutoGLM_GUI/adb_plus/touch.py +4 -9
- AutoGLM_GUI/agents/__init__.py +43 -12
- AutoGLM_GUI/agents/events.py +19 -0
- AutoGLM_GUI/agents/factory.py +31 -38
- AutoGLM_GUI/agents/glm/__init__.py +7 -0
- AutoGLM_GUI/agents/glm/agent.py +292 -0
- AutoGLM_GUI/agents/glm/message_builder.py +81 -0
- AutoGLM_GUI/agents/glm/parser.py +110 -0
- AutoGLM_GUI/agents/glm/prompts_en.py +77 -0
- AutoGLM_GUI/agents/glm/prompts_zh.py +75 -0
- AutoGLM_GUI/agents/mai/__init__.py +28 -0
- AutoGLM_GUI/agents/mai/agent.py +405 -0
- AutoGLM_GUI/agents/mai/parser.py +254 -0
- AutoGLM_GUI/agents/mai/prompts.py +103 -0
- AutoGLM_GUI/agents/mai/traj_memory.py +91 -0
- AutoGLM_GUI/agents/protocols.py +12 -8
- AutoGLM_GUI/agents/stream_runner.py +188 -0
- AutoGLM_GUI/api/__init__.py +40 -21
- AutoGLM_GUI/api/agents.py +157 -240
- AutoGLM_GUI/api/control.py +9 -6
- AutoGLM_GUI/api/devices.py +102 -12
- AutoGLM_GUI/api/history.py +78 -0
- AutoGLM_GUI/api/layered_agent.py +67 -15
- AutoGLM_GUI/api/media.py +64 -1
- AutoGLM_GUI/api/scheduled_tasks.py +98 -0
- AutoGLM_GUI/config.py +81 -0
- AutoGLM_GUI/config_manager.py +68 -51
- AutoGLM_GUI/device_manager.py +248 -29
- AutoGLM_GUI/device_protocol.py +1 -1
- AutoGLM_GUI/devices/adb_device.py +5 -10
- AutoGLM_GUI/devices/mock_device.py +4 -2
- AutoGLM_GUI/devices/remote_device.py +8 -3
- AutoGLM_GUI/history_manager.py +164 -0
- AutoGLM_GUI/i18n.py +81 -0
- AutoGLM_GUI/model/__init__.py +5 -0
- AutoGLM_GUI/model/message_builder.py +69 -0
- AutoGLM_GUI/model/types.py +24 -0
- AutoGLM_GUI/models/__init__.py +10 -0
- AutoGLM_GUI/models/history.py +96 -0
- AutoGLM_GUI/models/scheduled_task.py +71 -0
- AutoGLM_GUI/parsers/__init__.py +22 -0
- AutoGLM_GUI/parsers/base.py +50 -0
- AutoGLM_GUI/parsers/phone_parser.py +58 -0
- AutoGLM_GUI/phone_agent_manager.py +62 -396
- AutoGLM_GUI/platform_utils.py +26 -0
- AutoGLM_GUI/prompt_config.py +15 -0
- AutoGLM_GUI/prompts/__init__.py +32 -0
- AutoGLM_GUI/scheduler_manager.py +304 -0
- AutoGLM_GUI/schemas.py +234 -72
- AutoGLM_GUI/scrcpy_stream.py +142 -24
- AutoGLM_GUI/socketio_server.py +100 -27
- AutoGLM_GUI/static/assets/{about-_XNhzQZX.js → about-BQm96DAl.js} +1 -1
- AutoGLM_GUI/static/assets/alert-dialog-B42XxGPR.js +1 -0
- AutoGLM_GUI/static/assets/chat-C0L2gQYG.js +129 -0
- AutoGLM_GUI/static/assets/circle-alert-D4rSJh37.js +1 -0
- AutoGLM_GUI/static/assets/dialog-DZ78cEcj.js +45 -0
- AutoGLM_GUI/static/assets/history-DFBv7TGc.js +1 -0
- AutoGLM_GUI/static/assets/index-Bzyv2yQ2.css +1 -0
- AutoGLM_GUI/static/assets/{index-Cy8TmmHV.js → index-CmZSnDqc.js} +1 -1
- AutoGLM_GUI/static/assets/index-CssG-3TH.js +11 -0
- AutoGLM_GUI/static/assets/label-BCUzE_nm.js +1 -0
- AutoGLM_GUI/static/assets/logs-eoFxn5of.js +1 -0
- AutoGLM_GUI/static/assets/popover-DLsuV5Sx.js +1 -0
- AutoGLM_GUI/static/assets/scheduled-tasks-MyqGJvy_.js +1 -0
- AutoGLM_GUI/static/assets/square-pen-zGWYrdfj.js +1 -0
- AutoGLM_GUI/static/assets/textarea-BX6y7uM5.js +1 -0
- AutoGLM_GUI/static/assets/workflows-CYFs6ssC.js +1 -0
- AutoGLM_GUI/static/index.html +2 -2
- AutoGLM_GUI/types.py +17 -0
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.0.dist-info}/METADATA +137 -130
- autoglm_gui-1.5.0.dist-info/RECORD +157 -0
- AutoGLM_GUI/agents/mai_adapter.py +0 -627
- AutoGLM_GUI/api/dual_model.py +0 -317
- AutoGLM_GUI/dual_model/__init__.py +0 -53
- AutoGLM_GUI/dual_model/decision_model.py +0 -664
- AutoGLM_GUI/dual_model/dual_agent.py +0 -917
- AutoGLM_GUI/dual_model/protocols.py +0 -354
- AutoGLM_GUI/dual_model/vision_model.py +0 -442
- AutoGLM_GUI/mai_ui_adapter/agent_wrapper.py +0 -291
- AutoGLM_GUI/phone_agent_patches.py +0 -147
- AutoGLM_GUI/static/assets/chat-DwJpiAWf.js +0 -126
- AutoGLM_GUI/static/assets/dialog-B3uW4T8V.js +0 -45
- AutoGLM_GUI/static/assets/index-Cpv2gSF1.css +0 -1
- AutoGLM_GUI/static/assets/index-UYYauTly.js +0 -12
- AutoGLM_GUI/static/assets/workflows-Du_de-dt.js +0 -1
- autoglm_gui-1.4.1.dist-info/RECORD +0 -117
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.0.dist-info}/WHEEL +0 -0
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.0.dist-info}/entry_points.txt +0 -0
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""Timing configuration for Phone Agent.
|
|
2
|
+
|
|
3
|
+
This module defines all configurable waiting times used throughout the application.
|
|
4
|
+
Users can customize these values by modifying this file or by setting environment variables.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class ActionTimingConfig:
|
|
13
|
+
"""Configuration for action handler timing delays."""
|
|
14
|
+
|
|
15
|
+
# Text input related delays (in seconds)
|
|
16
|
+
keyboard_switch_delay: float = 1.0 # Delay after switching to ADB keyboard
|
|
17
|
+
text_clear_delay: float = 1.0 # Delay after clearing text
|
|
18
|
+
text_input_delay: float = 1.0 # Delay after typing text
|
|
19
|
+
keyboard_restore_delay: float = 1.0 # Delay after restoring original keyboard
|
|
20
|
+
|
|
21
|
+
def __post_init__(self):
|
|
22
|
+
"""Load values from environment variables if present."""
|
|
23
|
+
self.keyboard_switch_delay = float(
|
|
24
|
+
os.getenv("PHONE_AGENT_KEYBOARD_SWITCH_DELAY", self.keyboard_switch_delay)
|
|
25
|
+
)
|
|
26
|
+
self.text_clear_delay = float(
|
|
27
|
+
os.getenv("PHONE_AGENT_TEXT_CLEAR_DELAY", self.text_clear_delay)
|
|
28
|
+
)
|
|
29
|
+
self.text_input_delay = float(
|
|
30
|
+
os.getenv("PHONE_AGENT_TEXT_INPUT_DELAY", self.text_input_delay)
|
|
31
|
+
)
|
|
32
|
+
self.keyboard_restore_delay = float(
|
|
33
|
+
os.getenv("PHONE_AGENT_KEYBOARD_RESTORE_DELAY", self.keyboard_restore_delay)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class DeviceTimingConfig:
|
|
39
|
+
"""Configuration for device operation timing delays."""
|
|
40
|
+
|
|
41
|
+
# Default delays for various device operations (in seconds)
|
|
42
|
+
default_tap_delay: float = 1.0 # Default delay after tap
|
|
43
|
+
default_double_tap_delay: float = 1.0 # Default delay after double tap
|
|
44
|
+
double_tap_interval: float = 0.1 # Interval between two taps in double tap
|
|
45
|
+
default_long_press_delay: float = 1.0 # Default delay after long press
|
|
46
|
+
default_swipe_delay: float = 1.0 # Default delay after swipe
|
|
47
|
+
default_back_delay: float = 1.0 # Default delay after back button
|
|
48
|
+
default_home_delay: float = 1.0 # Default delay after home button
|
|
49
|
+
default_launch_delay: float = 1.0 # Default delay after launching app
|
|
50
|
+
|
|
51
|
+
def __post_init__(self):
|
|
52
|
+
"""Load values from environment variables if present."""
|
|
53
|
+
self.default_tap_delay = float(
|
|
54
|
+
os.getenv("PHONE_AGENT_TAP_DELAY", self.default_tap_delay)
|
|
55
|
+
)
|
|
56
|
+
self.default_double_tap_delay = float(
|
|
57
|
+
os.getenv("PHONE_AGENT_DOUBLE_TAP_DELAY", self.default_double_tap_delay)
|
|
58
|
+
)
|
|
59
|
+
self.double_tap_interval = float(
|
|
60
|
+
os.getenv("PHONE_AGENT_DOUBLE_TAP_INTERVAL", self.double_tap_interval)
|
|
61
|
+
)
|
|
62
|
+
self.default_long_press_delay = float(
|
|
63
|
+
os.getenv("PHONE_AGENT_LONG_PRESS_DELAY", self.default_long_press_delay)
|
|
64
|
+
)
|
|
65
|
+
self.default_swipe_delay = float(
|
|
66
|
+
os.getenv("PHONE_AGENT_SWIPE_DELAY", self.default_swipe_delay)
|
|
67
|
+
)
|
|
68
|
+
self.default_back_delay = float(
|
|
69
|
+
os.getenv("PHONE_AGENT_BACK_DELAY", self.default_back_delay)
|
|
70
|
+
)
|
|
71
|
+
self.default_home_delay = float(
|
|
72
|
+
os.getenv("PHONE_AGENT_HOME_DELAY", self.default_home_delay)
|
|
73
|
+
)
|
|
74
|
+
self.default_launch_delay = float(
|
|
75
|
+
os.getenv("PHONE_AGENT_LAUNCH_DELAY", self.default_launch_delay)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class ConnectionTimingConfig:
|
|
81
|
+
"""Configuration for ADB connection timing delays."""
|
|
82
|
+
|
|
83
|
+
# ADB server and connection delays (in seconds)
|
|
84
|
+
adb_restart_delay: float = 2.0 # Wait time after enabling TCP/IP mode
|
|
85
|
+
server_restart_delay: float = (
|
|
86
|
+
1.0 # Wait time between killing and starting ADB server
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
def __post_init__(self):
|
|
90
|
+
"""Load values from environment variables if present."""
|
|
91
|
+
self.adb_restart_delay = float(
|
|
92
|
+
os.getenv("PHONE_AGENT_ADB_RESTART_DELAY", self.adb_restart_delay)
|
|
93
|
+
)
|
|
94
|
+
self.server_restart_delay = float(
|
|
95
|
+
os.getenv("PHONE_AGENT_SERVER_RESTART_DELAY", self.server_restart_delay)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class TimingConfig:
|
|
101
|
+
"""Master timing configuration combining all timing settings."""
|
|
102
|
+
|
|
103
|
+
action: ActionTimingConfig
|
|
104
|
+
device: DeviceTimingConfig
|
|
105
|
+
connection: ConnectionTimingConfig
|
|
106
|
+
|
|
107
|
+
def __init__(self):
|
|
108
|
+
"""Initialize all timing configurations."""
|
|
109
|
+
self.action = ActionTimingConfig()
|
|
110
|
+
self.device = DeviceTimingConfig()
|
|
111
|
+
self.connection = ConnectionTimingConfig()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# Global timing configuration instance
|
|
115
|
+
# Users can modify these values at runtime or through environment variables
|
|
116
|
+
TIMING_CONFIG = TimingConfig()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def get_timing_config() -> TimingConfig:
|
|
120
|
+
"""
|
|
121
|
+
Get the global timing configuration.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
The global TimingConfig instance.
|
|
125
|
+
"""
|
|
126
|
+
return TIMING_CONFIG
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def update_timing_config(
|
|
130
|
+
action: ActionTimingConfig | None = None,
|
|
131
|
+
device: DeviceTimingConfig | None = None,
|
|
132
|
+
connection: ConnectionTimingConfig | None = None,
|
|
133
|
+
) -> None:
|
|
134
|
+
"""
|
|
135
|
+
Update the global timing configuration.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
action: New action timing configuration.
|
|
139
|
+
device: New device timing configuration.
|
|
140
|
+
connection: New connection timing configuration.
|
|
141
|
+
|
|
142
|
+
Example:
|
|
143
|
+
>>> from AutoGLM_GUI.adb.timing import update_timing_config, ActionTimingConfig
|
|
144
|
+
>>> custom_action = ActionTimingConfig(
|
|
145
|
+
... keyboard_switch_delay=0.5,
|
|
146
|
+
... text_input_delay=0.5
|
|
147
|
+
... )
|
|
148
|
+
>>> update_timing_config(action=custom_action)
|
|
149
|
+
"""
|
|
150
|
+
global TIMING_CONFIG
|
|
151
|
+
if action is not None:
|
|
152
|
+
TIMING_CONFIG.action = action
|
|
153
|
+
if device is not None:
|
|
154
|
+
TIMING_CONFIG.device = device
|
|
155
|
+
if connection is not None:
|
|
156
|
+
TIMING_CONFIG.connection = connection
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
__all__ = [
|
|
160
|
+
"ActionTimingConfig",
|
|
161
|
+
"DeviceTimingConfig",
|
|
162
|
+
"ConnectionTimingConfig",
|
|
163
|
+
"TimingConfig",
|
|
164
|
+
"TIMING_CONFIG",
|
|
165
|
+
"get_timing_config",
|
|
166
|
+
"update_timing_config",
|
|
167
|
+
]
|
|
@@ -104,8 +104,10 @@ class ADBKeyboardInstaller:
|
|
|
104
104
|
from importlib.resources import files
|
|
105
105
|
|
|
106
106
|
logger.debug("Searching for bundled APK in wheel package")
|
|
107
|
-
resource =
|
|
108
|
-
"
|
|
107
|
+
resource = (
|
|
108
|
+
files("AutoGLM_GUI")
|
|
109
|
+
.joinpath("resources/apks")
|
|
110
|
+
.joinpath(ADB_KEYBOARD_APK_FILENAME)
|
|
109
111
|
)
|
|
110
112
|
# Convert to Path
|
|
111
113
|
if hasattr(resource, "read_bytes"):
|
|
@@ -13,6 +13,8 @@ from io import BytesIO
|
|
|
13
13
|
|
|
14
14
|
from PIL import Image
|
|
15
15
|
|
|
16
|
+
from AutoGLM_GUI.exceptions import DeviceNotAvailableError
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
PNG_SIGNATURE = b"\x89PNG\r\n\x1a\n"
|
|
18
20
|
|
|
@@ -44,9 +46,13 @@ def capture_screenshot(
|
|
|
44
46
|
|
|
45
47
|
Returns:
|
|
46
48
|
Screenshot object; falls back to a black image on failure.
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
DeviceNotAvailableError: When device is not found or offline.
|
|
47
52
|
"""
|
|
48
53
|
attempts = max(1, retries + 1)
|
|
49
54
|
for _ in range(attempts):
|
|
55
|
+
# _try_capture may raise DeviceNotAvailableError, let it propagate
|
|
50
56
|
data = _try_capture(device_id=device_id, adb_path=adb_path, timeout=timeout)
|
|
51
57
|
if not data:
|
|
52
58
|
continue
|
|
@@ -72,7 +78,11 @@ def capture_screenshot(
|
|
|
72
78
|
|
|
73
79
|
|
|
74
80
|
def _try_capture(device_id: str | None, adb_path: str, timeout: int) -> bytes | None:
|
|
75
|
-
"""Run exec-out screencap and return raw bytes or None on failure.
|
|
81
|
+
"""Run exec-out screencap and return raw bytes or None on failure.
|
|
82
|
+
|
|
83
|
+
Raises:
|
|
84
|
+
DeviceNotAvailableError: When device is not found or offline.
|
|
85
|
+
"""
|
|
76
86
|
cmd: list[str | bytes] = [adb_path]
|
|
77
87
|
if device_id:
|
|
78
88
|
cmd.extend(["-s", device_id])
|
|
@@ -85,9 +95,20 @@ def _try_capture(device_id: str | None, adb_path: str, timeout: int) -> bytes |
|
|
|
85
95
|
timeout=timeout,
|
|
86
96
|
)
|
|
87
97
|
if result.returncode != 0:
|
|
98
|
+
# Check for device not found or offline errors
|
|
99
|
+
stderr = (
|
|
100
|
+
result.stderr.decode("utf-8", errors="ignore") if result.stderr else ""
|
|
101
|
+
)
|
|
102
|
+
stderr_lower = stderr.lower()
|
|
103
|
+
if "device not found" in stderr_lower or "offline" in stderr_lower:
|
|
104
|
+
raise DeviceNotAvailableError(
|
|
105
|
+
f"Device {device_id} not found or offline"
|
|
106
|
+
)
|
|
88
107
|
return None
|
|
89
108
|
# stdout should hold the PNG data
|
|
90
109
|
return result.stdout if isinstance(result.stdout, (bytes, bytearray)) else None
|
|
110
|
+
except DeviceNotAvailableError:
|
|
111
|
+
raise # Re-raise to caller
|
|
91
112
|
except Exception:
|
|
92
113
|
return None
|
|
93
114
|
|
AutoGLM_GUI/adb_plus/serial.py
CHANGED
|
@@ -49,12 +49,22 @@ def extract_serial_from_mdns(device_id: str) -> Optional[str]:
|
|
|
49
49
|
return None
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
# Serial number properties to try, in order of preference
|
|
53
|
+
_SERIAL_PROPS = [
|
|
54
|
+
"ro.serialno",
|
|
55
|
+
"ro.boot.serialno",
|
|
56
|
+
"ro.product.serial",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_device_serial(device_id: str, adb_path: str = "adb") -> str:
|
|
53
61
|
"""
|
|
54
62
|
Get the real hardware serial number of a device.
|
|
55
63
|
|
|
56
64
|
For mDNS devices, attempts to extract serial from service name first.
|
|
57
65
|
Falls back to getprop for USB/WiFi devices or if extraction fails.
|
|
66
|
+
If all methods fail, returns device_id as fallback (for emulators or
|
|
67
|
+
restricted devices that don't expose serial number).
|
|
58
68
|
|
|
59
69
|
This works for both USB and WiFi connected devices,
|
|
60
70
|
returning the actual hardware serial number (ro.serialno).
|
|
@@ -64,7 +74,8 @@ def get_device_serial(device_id: str, adb_path: str = "adb") -> str | None:
|
|
|
64
74
|
adb_path: Path to adb executable (default: "adb")
|
|
65
75
|
|
|
66
76
|
Returns:
|
|
67
|
-
The device hardware serial number
|
|
77
|
+
The device hardware serial number. Always returns a value - uses
|
|
78
|
+
device_id as fallback if serial cannot be obtained.
|
|
68
79
|
"""
|
|
69
80
|
from AutoGLM_GUI.logger import logger
|
|
70
81
|
|
|
@@ -74,21 +85,28 @@ def get_device_serial(device_id: str, adb_path: str = "adb") -> str | None:
|
|
|
74
85
|
logger.debug(f"Extracted serial from mDNS name: {device_id} → {mdns_serial}")
|
|
75
86
|
return mdns_serial
|
|
76
87
|
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
88
|
+
# Try multiple serial properties (some emulators use different props)
|
|
89
|
+
for prop in _SERIAL_PROPS:
|
|
90
|
+
try:
|
|
91
|
+
result = run_cmd_silently_sync(
|
|
92
|
+
[adb_path, "-s", device_id, "shell", "getprop", prop],
|
|
93
|
+
timeout=5, # Increased timeout for network devices
|
|
94
|
+
)
|
|
95
|
+
if result.returncode == 0:
|
|
96
|
+
serial = result.stdout.strip()
|
|
97
|
+
# Filter out error messages and empty values
|
|
98
|
+
if serial and not serial.startswith("error:") and serial != "unknown":
|
|
99
|
+
logger.debug(f"Got serial via {prop}: {device_id} → {serial}")
|
|
100
|
+
return serial
|
|
101
|
+
except Exception as e:
|
|
102
|
+
logger.debug(f"Failed to get serial via {prop} for {device_id}: {e}")
|
|
103
|
+
continue
|
|
104
|
+
|
|
105
|
+
# Fallback: Use device_id itself as serial
|
|
106
|
+
# This handles emulators (MuMu, Nox, etc.) and restricted devices
|
|
107
|
+
# that don't expose serial number via getprop
|
|
108
|
+
logger.warning(
|
|
109
|
+
f"Could not get hardware serial for {device_id}, "
|
|
110
|
+
f"using device_id as serial (emulator/restricted device)"
|
|
111
|
+
)
|
|
112
|
+
return device_id
|
AutoGLM_GUI/adb_plus/touch.py
CHANGED
|
@@ -3,12 +3,7 @@
|
|
|
3
3
|
import subprocess
|
|
4
4
|
import time
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
def _get_adb_prefix(device_id: str | None, adb_path: str = "adb") -> list[str]:
|
|
8
|
-
"""Get ADB command prefix with optional device specifier."""
|
|
9
|
-
if device_id:
|
|
10
|
-
return [adb_path, "-s", device_id]
|
|
11
|
-
return [adb_path]
|
|
6
|
+
from AutoGLM_GUI.platform_utils import build_adb_command
|
|
12
7
|
|
|
13
8
|
|
|
14
9
|
def touch_down(
|
|
@@ -28,7 +23,7 @@ def touch_down(
|
|
|
28
23
|
delay: Delay in seconds after event (default: 0.0 for real-time).
|
|
29
24
|
adb_path: Path to adb binary.
|
|
30
25
|
"""
|
|
31
|
-
adb_prefix =
|
|
26
|
+
adb_prefix = build_adb_command(device_id, adb_path)
|
|
32
27
|
|
|
33
28
|
subprocess.run(
|
|
34
29
|
adb_prefix + ["shell", "input", "motionevent", "DOWN", str(x), str(y)],
|
|
@@ -55,7 +50,7 @@ def touch_move(
|
|
|
55
50
|
delay: Delay in seconds after event (default: 0.0 for real-time).
|
|
56
51
|
adb_path: Path to adb binary.
|
|
57
52
|
"""
|
|
58
|
-
adb_prefix =
|
|
53
|
+
adb_prefix = build_adb_command(device_id, adb_path)
|
|
59
54
|
|
|
60
55
|
subprocess.run(
|
|
61
56
|
adb_prefix + ["shell", "input", "motionevent", "MOVE", str(x), str(y)],
|
|
@@ -82,7 +77,7 @@ def touch_up(
|
|
|
82
77
|
delay: Delay in seconds after event (default: 0.0 for real-time).
|
|
83
78
|
adb_path: Path to adb binary.
|
|
84
79
|
"""
|
|
85
|
-
adb_prefix =
|
|
80
|
+
adb_prefix = build_adb_command(device_id, adb_path)
|
|
86
81
|
|
|
87
82
|
subprocess.run(
|
|
88
83
|
adb_prefix + ["shell", "input", "motionevent", "UP", str(x), str(y)],
|
AutoGLM_GUI/agents/__init__.py
CHANGED
|
@@ -1,20 +1,51 @@
|
|
|
1
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Callable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def register_agent(agent_type: str, creator: Callable) -> None:
|
|
7
|
+
from .factory import register_agent as _register_agent
|
|
8
|
+
|
|
9
|
+
_register_agent(agent_type=agent_type, creator=creator)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def create_agent(
|
|
13
|
+
agent_type: str,
|
|
14
|
+
model_config,
|
|
15
|
+
agent_config,
|
|
16
|
+
agent_specific_config,
|
|
17
|
+
device,
|
|
18
|
+
takeover_callback: Callable | None = None,
|
|
19
|
+
confirmation_callback: Callable | None = None,
|
|
20
|
+
):
|
|
21
|
+
from .factory import create_agent as _create_agent
|
|
22
|
+
|
|
23
|
+
return _create_agent(
|
|
24
|
+
agent_type=agent_type,
|
|
25
|
+
model_config=model_config,
|
|
26
|
+
agent_config=agent_config,
|
|
27
|
+
agent_specific_config=agent_specific_config,
|
|
28
|
+
device=device,
|
|
29
|
+
takeover_callback=takeover_callback,
|
|
30
|
+
confirmation_callback=confirmation_callback,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def list_agent_types() -> list[str]:
|
|
35
|
+
from .factory import list_agent_types as _list_agent_types
|
|
36
|
+
|
|
37
|
+
return _list_agent_types()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def is_agent_type_registered(agent_type: str) -> bool:
|
|
41
|
+
from .factory import is_agent_type_registered as _is_agent_type_registered
|
|
42
|
+
|
|
43
|
+
return _is_agent_type_registered(agent_type)
|
|
2
44
|
|
|
3
|
-
from .factory import (
|
|
4
|
-
create_agent,
|
|
5
|
-
is_agent_type_registered,
|
|
6
|
-
list_agent_types,
|
|
7
|
-
register_agent,
|
|
8
|
-
)
|
|
9
|
-
from .mai_adapter import MAIAgentAdapter, MAIAgentConfig
|
|
10
45
|
|
|
11
46
|
__all__ = [
|
|
12
|
-
# Factory
|
|
13
47
|
"create_agent",
|
|
14
48
|
"register_agent",
|
|
15
49
|
"list_agent_types",
|
|
16
50
|
"is_agent_type_registered",
|
|
17
|
-
# Adapters
|
|
18
|
-
"MAIAgentAdapter",
|
|
19
|
-
"MAIAgentConfig",
|
|
20
51
|
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Any, TypedDict
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AgentEventType(str, Enum):
|
|
6
|
+
"""Agent 事件类型."""
|
|
7
|
+
|
|
8
|
+
THINKING = "thinking_chunk"
|
|
9
|
+
STEP = "step"
|
|
10
|
+
DONE = "done"
|
|
11
|
+
ERROR = "error"
|
|
12
|
+
ABORTED = "aborted"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AgentEvent(TypedDict):
|
|
16
|
+
"""Agent 事件(统一类型)."""
|
|
17
|
+
|
|
18
|
+
type: str # 使用字符串以兼容现有 SSE 类型
|
|
19
|
+
data: dict[str, Any]
|
AutoGLM_GUI/agents/factory.py
CHANGED
|
@@ -6,20 +6,14 @@ making it easy to add new agent types without modifying existing code.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import Callable, Dict
|
|
10
10
|
|
|
11
|
+
from AutoGLM_GUI.config import AgentConfig, ModelConfig
|
|
11
12
|
from AutoGLM_GUI.logger import logger
|
|
12
13
|
from AutoGLM_GUI.types import AgentSpecificConfig
|
|
13
14
|
|
|
14
15
|
from .protocols import BaseAgent
|
|
15
16
|
|
|
16
|
-
if TYPE_CHECKING:
|
|
17
|
-
from phone_agent import PhoneAgent
|
|
18
|
-
from phone_agent.agent import AgentConfig
|
|
19
|
-
from phone_agent.model import ModelConfig
|
|
20
|
-
|
|
21
|
-
from .mai_adapter import MAIAgentAdapter
|
|
22
|
-
|
|
23
17
|
|
|
24
18
|
# Agent registry: agent_type -> (creator_function, config_schema)
|
|
25
19
|
AGENT_REGISTRY: Dict[str, Callable] = {}
|
|
@@ -52,12 +46,13 @@ def register_agent(
|
|
|
52
46
|
|
|
53
47
|
def create_agent(
|
|
54
48
|
agent_type: str,
|
|
55
|
-
model_config:
|
|
56
|
-
agent_config:
|
|
49
|
+
model_config: ModelConfig,
|
|
50
|
+
agent_config: AgentConfig,
|
|
57
51
|
agent_specific_config: AgentSpecificConfig,
|
|
52
|
+
device,
|
|
58
53
|
takeover_callback: Callable | None = None,
|
|
59
54
|
confirmation_callback: Callable | None = None,
|
|
60
|
-
) ->
|
|
55
|
+
) -> BaseAgent:
|
|
61
56
|
"""
|
|
62
57
|
Create an agent instance using the factory pattern.
|
|
63
58
|
|
|
@@ -66,6 +61,7 @@ def create_agent(
|
|
|
66
61
|
model_config: Model configuration
|
|
67
62
|
agent_config: Agent configuration
|
|
68
63
|
agent_specific_config: Agent-specific configuration (e.g., MAIConfig fields)
|
|
64
|
+
device: DeviceProtocol instance (provided by PhoneAgentManager)
|
|
69
65
|
takeover_callback: Takeover callback
|
|
70
66
|
confirmation_callback: Confirmation callback
|
|
71
67
|
|
|
@@ -88,6 +84,7 @@ def create_agent(
|
|
|
88
84
|
model_config=model_config,
|
|
89
85
|
agent_config=agent_config,
|
|
90
86
|
agent_specific_config=agent_specific_config,
|
|
87
|
+
device=device,
|
|
91
88
|
takeover_callback=takeover_callback,
|
|
92
89
|
confirmation_callback=confirmation_callback,
|
|
93
90
|
)
|
|
@@ -111,50 +108,46 @@ def is_agent_type_registered(agent_type: str) -> bool:
|
|
|
111
108
|
# ==================== Built-in Agent Creators ====================
|
|
112
109
|
|
|
113
110
|
|
|
114
|
-
def
|
|
115
|
-
model_config:
|
|
116
|
-
agent_config:
|
|
111
|
+
def _create_glm_agent_v2(
|
|
112
|
+
model_config: ModelConfig,
|
|
113
|
+
agent_config: AgentConfig,
|
|
117
114
|
agent_specific_config: AgentSpecificConfig,
|
|
115
|
+
device,
|
|
118
116
|
takeover_callback: Callable | None = None,
|
|
119
117
|
confirmation_callback: Callable | None = None,
|
|
120
|
-
) ->
|
|
121
|
-
from
|
|
118
|
+
) -> BaseAgent:
|
|
119
|
+
from .glm.agent import GLMAgent
|
|
122
120
|
|
|
123
|
-
return
|
|
121
|
+
return GLMAgent(
|
|
124
122
|
model_config=model_config,
|
|
125
123
|
agent_config=agent_config,
|
|
126
|
-
|
|
124
|
+
device=device,
|
|
127
125
|
confirmation_callback=confirmation_callback,
|
|
126
|
+
takeover_callback=takeover_callback,
|
|
128
127
|
)
|
|
129
128
|
|
|
130
129
|
|
|
131
|
-
def
|
|
132
|
-
model_config:
|
|
133
|
-
agent_config:
|
|
130
|
+
def _create_internal_mai_agent(
|
|
131
|
+
model_config: ModelConfig,
|
|
132
|
+
agent_config: AgentConfig,
|
|
134
133
|
agent_specific_config: AgentSpecificConfig,
|
|
134
|
+
device,
|
|
135
135
|
takeover_callback: Callable | None = None,
|
|
136
136
|
confirmation_callback: Callable | None = None,
|
|
137
|
-
) ->
|
|
138
|
-
from .
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
mai_config = MAIAgentConfig(
|
|
142
|
-
history_n=agent_specific_config.get("history_n", 3),
|
|
143
|
-
max_pixels=agent_specific_config.get("max_pixels"),
|
|
144
|
-
min_pixels=agent_specific_config.get("min_pixels"),
|
|
145
|
-
tools=agent_specific_config.get("tools"),
|
|
146
|
-
use_mai_prompt=agent_specific_config.get("use_mai_prompt", False),
|
|
147
|
-
)
|
|
137
|
+
) -> BaseAgent:
|
|
138
|
+
from .mai.agent import InternalMAIAgent
|
|
139
|
+
|
|
140
|
+
history_n = agent_specific_config.get("history_n", 3)
|
|
148
141
|
|
|
149
|
-
return
|
|
142
|
+
return InternalMAIAgent(
|
|
150
143
|
model_config=model_config,
|
|
151
144
|
agent_config=agent_config,
|
|
152
|
-
|
|
153
|
-
|
|
145
|
+
device=device,
|
|
146
|
+
history_n=history_n,
|
|
154
147
|
confirmation_callback=confirmation_callback,
|
|
148
|
+
takeover_callback=takeover_callback,
|
|
155
149
|
)
|
|
156
150
|
|
|
157
151
|
|
|
158
|
-
|
|
159
|
-
register_agent("
|
|
160
|
-
register_agent("mai", _create_mai_agent)
|
|
152
|
+
register_agent("glm", _create_glm_agent_v2)
|
|
153
|
+
register_agent("mai", _create_internal_mai_agent)
|