autoglm-gui 1.4.1__py3-none-any.whl → 1.5.1__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.
Files changed (135) hide show
  1. AutoGLM_GUI/__init__.py +11 -0
  2. AutoGLM_GUI/__main__.py +26 -4
  3. AutoGLM_GUI/actions/__init__.py +6 -0
  4. phone_agent/actions/handler_ios.py → AutoGLM_GUI/actions/handler.py +30 -112
  5. AutoGLM_GUI/actions/types.py +15 -0
  6. {phone_agent → AutoGLM_GUI}/adb/__init__.py +25 -23
  7. {phone_agent → AutoGLM_GUI}/adb/connection.py +5 -40
  8. {phone_agent → AutoGLM_GUI}/adb/device.py +12 -94
  9. {phone_agent → AutoGLM_GUI}/adb/input.py +6 -47
  10. AutoGLM_GUI/adb/screenshot.py +11 -0
  11. {phone_agent/config → AutoGLM_GUI/adb}/timing.py +1 -1
  12. AutoGLM_GUI/adb_plus/keyboard_installer.py +4 -2
  13. AutoGLM_GUI/adb_plus/screenshot.py +22 -1
  14. AutoGLM_GUI/adb_plus/serial.py +38 -20
  15. AutoGLM_GUI/adb_plus/touch.py +4 -9
  16. AutoGLM_GUI/agents/__init__.py +43 -12
  17. AutoGLM_GUI/agents/events.py +19 -0
  18. AutoGLM_GUI/agents/factory.py +31 -38
  19. AutoGLM_GUI/agents/glm/__init__.py +7 -0
  20. AutoGLM_GUI/agents/glm/agent.py +297 -0
  21. AutoGLM_GUI/agents/glm/message_builder.py +81 -0
  22. AutoGLM_GUI/agents/glm/parser.py +110 -0
  23. {phone_agent/config → AutoGLM_GUI/agents/glm}/prompts_en.py +7 -9
  24. {phone_agent/config → AutoGLM_GUI/agents/glm}/prompts_zh.py +18 -25
  25. AutoGLM_GUI/agents/mai/__init__.py +28 -0
  26. AutoGLM_GUI/agents/mai/agent.py +408 -0
  27. AutoGLM_GUI/agents/mai/parser.py +254 -0
  28. AutoGLM_GUI/agents/mai/prompts.py +103 -0
  29. AutoGLM_GUI/agents/mai/traj_memory.py +91 -0
  30. AutoGLM_GUI/agents/protocols.py +12 -8
  31. AutoGLM_GUI/agents/stream_runner.py +193 -0
  32. AutoGLM_GUI/api/__init__.py +40 -21
  33. AutoGLM_GUI/api/agents.py +181 -239
  34. AutoGLM_GUI/api/control.py +9 -6
  35. AutoGLM_GUI/api/devices.py +102 -12
  36. AutoGLM_GUI/api/history.py +104 -0
  37. AutoGLM_GUI/api/layered_agent.py +67 -15
  38. AutoGLM_GUI/api/media.py +64 -1
  39. AutoGLM_GUI/api/scheduled_tasks.py +98 -0
  40. AutoGLM_GUI/config.py +81 -0
  41. AutoGLM_GUI/config_manager.py +68 -51
  42. AutoGLM_GUI/device_manager.py +248 -29
  43. AutoGLM_GUI/device_protocol.py +1 -1
  44. AutoGLM_GUI/devices/adb_device.py +5 -10
  45. AutoGLM_GUI/devices/mock_device.py +4 -2
  46. AutoGLM_GUI/devices/remote_device.py +8 -3
  47. AutoGLM_GUI/history_manager.py +164 -0
  48. AutoGLM_GUI/model/__init__.py +5 -0
  49. AutoGLM_GUI/model/message_builder.py +69 -0
  50. AutoGLM_GUI/model/types.py +24 -0
  51. AutoGLM_GUI/models/__init__.py +10 -0
  52. AutoGLM_GUI/models/history.py +140 -0
  53. AutoGLM_GUI/models/scheduled_task.py +71 -0
  54. AutoGLM_GUI/parsers/__init__.py +22 -0
  55. AutoGLM_GUI/parsers/base.py +50 -0
  56. AutoGLM_GUI/parsers/phone_parser.py +58 -0
  57. AutoGLM_GUI/phone_agent_manager.py +62 -396
  58. AutoGLM_GUI/platform_utils.py +26 -0
  59. AutoGLM_GUI/prompt_config.py +15 -0
  60. AutoGLM_GUI/prompts/__init__.py +32 -0
  61. AutoGLM_GUI/scheduler_manager.py +350 -0
  62. AutoGLM_GUI/schemas.py +246 -72
  63. AutoGLM_GUI/scrcpy_stream.py +142 -24
  64. AutoGLM_GUI/socketio_server.py +100 -27
  65. AutoGLM_GUI/static/assets/{about-_XNhzQZX.js → about-CfwX1Cmc.js} +1 -1
  66. AutoGLM_GUI/static/assets/alert-dialog-CtGlN2IJ.js +1 -0
  67. AutoGLM_GUI/static/assets/chat-BYa-foUI.js +129 -0
  68. AutoGLM_GUI/static/assets/circle-alert-t08bEMPO.js +1 -0
  69. AutoGLM_GUI/static/assets/dialog-FNwZJFwk.js +45 -0
  70. AutoGLM_GUI/static/assets/eye-D0UPWCWC.js +1 -0
  71. AutoGLM_GUI/static/assets/history-CRo95B7i.js +1 -0
  72. AutoGLM_GUI/static/assets/{index-Cy8TmmHV.js → index-BaLMSqd3.js} +1 -1
  73. AutoGLM_GUI/static/assets/index-CTHbFvKl.js +11 -0
  74. AutoGLM_GUI/static/assets/index-CV7jGxGm.css +1 -0
  75. AutoGLM_GUI/static/assets/label-DJFevVmr.js +1 -0
  76. AutoGLM_GUI/static/assets/logs-RW09DyYY.js +1 -0
  77. AutoGLM_GUI/static/assets/popover--JTJrE5v.js +1 -0
  78. AutoGLM_GUI/static/assets/scheduled-tasks-DTRKsQXF.js +1 -0
  79. AutoGLM_GUI/static/assets/square-pen-CPK_K680.js +1 -0
  80. AutoGLM_GUI/static/assets/textarea-PRmVnWq5.js +1 -0
  81. AutoGLM_GUI/static/assets/workflows-CdcsAoaT.js +1 -0
  82. AutoGLM_GUI/static/index.html +2 -2
  83. AutoGLM_GUI/types.py +17 -0
  84. {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/METADATA +179 -130
  85. autoglm_gui-1.5.1.dist-info/RECORD +118 -0
  86. AutoGLM_GUI/agents/mai_adapter.py +0 -627
  87. AutoGLM_GUI/api/dual_model.py +0 -317
  88. AutoGLM_GUI/device_adapter.py +0 -263
  89. AutoGLM_GUI/dual_model/__init__.py +0 -53
  90. AutoGLM_GUI/dual_model/decision_model.py +0 -664
  91. AutoGLM_GUI/dual_model/dual_agent.py +0 -917
  92. AutoGLM_GUI/dual_model/protocols.py +0 -354
  93. AutoGLM_GUI/dual_model/vision_model.py +0 -442
  94. AutoGLM_GUI/mai_ui_adapter/agent_wrapper.py +0 -291
  95. AutoGLM_GUI/phone_agent_patches.py +0 -147
  96. AutoGLM_GUI/static/assets/chat-DwJpiAWf.js +0 -126
  97. AutoGLM_GUI/static/assets/dialog-B3uW4T8V.js +0 -45
  98. AutoGLM_GUI/static/assets/index-Cpv2gSF1.css +0 -1
  99. AutoGLM_GUI/static/assets/index-UYYauTly.js +0 -12
  100. AutoGLM_GUI/static/assets/workflows-Du_de-dt.js +0 -1
  101. autoglm_gui-1.4.1.dist-info/RECORD +0 -117
  102. mai_agent/base.py +0 -137
  103. mai_agent/mai_grounding_agent.py +0 -263
  104. mai_agent/mai_naivigation_agent.py +0 -526
  105. mai_agent/prompt.py +0 -148
  106. mai_agent/unified_memory.py +0 -67
  107. mai_agent/utils.py +0 -73
  108. phone_agent/__init__.py +0 -12
  109. phone_agent/actions/__init__.py +0 -5
  110. phone_agent/actions/handler.py +0 -400
  111. phone_agent/adb/screenshot.py +0 -108
  112. phone_agent/agent.py +0 -253
  113. phone_agent/agent_ios.py +0 -277
  114. phone_agent/config/__init__.py +0 -53
  115. phone_agent/config/apps_harmonyos.py +0 -256
  116. phone_agent/config/apps_ios.py +0 -339
  117. phone_agent/config/prompts.py +0 -80
  118. phone_agent/device_factory.py +0 -166
  119. phone_agent/hdc/__init__.py +0 -53
  120. phone_agent/hdc/connection.py +0 -384
  121. phone_agent/hdc/device.py +0 -269
  122. phone_agent/hdc/input.py +0 -145
  123. phone_agent/hdc/screenshot.py +0 -127
  124. phone_agent/model/__init__.py +0 -5
  125. phone_agent/model/client.py +0 -290
  126. phone_agent/xctest/__init__.py +0 -47
  127. phone_agent/xctest/connection.py +0 -379
  128. phone_agent/xctest/device.py +0 -472
  129. phone_agent/xctest/input.py +0 -311
  130. phone_agent/xctest/screenshot.py +0 -226
  131. {phone_agent/config → AutoGLM_GUI/adb}/apps.py +0 -0
  132. {phone_agent/config → AutoGLM_GUI}/i18n.py +0 -0
  133. {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/WHEEL +0 -0
  134. {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/entry_points.txt +0 -0
  135. {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/licenses/LICENSE +0 -0
AutoGLM_GUI/__init__.py CHANGED
@@ -5,6 +5,9 @@ import sys
5
5
  from functools import wraps
6
6
  from importlib import metadata
7
7
 
8
+ from AutoGLM_GUI.config import AgentConfig, ModelConfig, StepResult
9
+ from AutoGLM_GUI.logger import logger
10
+
8
11
  # 修复 Windows 编码问题 - 必须在所有其他导入之前
9
12
  if sys.platform == "win32":
10
13
  import codecs
@@ -58,3 +61,11 @@ try:
58
61
  __version__ = metadata.version("autoglm-gui")
59
62
  except metadata.PackageNotFoundError:
60
63
  __version__ = "unknown"
64
+
65
+ __all__ = [
66
+ "__version__",
67
+ "ModelConfig",
68
+ "AgentConfig",
69
+ "StepResult",
70
+ "logger",
71
+ ]
AutoGLM_GUI/__main__.py CHANGED
@@ -44,19 +44,25 @@ def find_available_port(
44
44
  )
45
45
 
46
46
 
47
- def open_browser(host: str, port: int, delay: float = 1.5) -> None:
47
+ def open_browser(
48
+ host: str, port: int, use_ssl: bool = False, delay: float = 1.5
49
+ ) -> None:
48
50
  """Open browser after a delay to ensure server is ready.
49
51
 
50
52
  Args:
51
53
  host: Server host
52
54
  port: Server port
55
+ use_ssl: Whether to use HTTPS
53
56
  delay: Delay in seconds before opening browser
54
57
  """
55
58
 
56
59
  def _open():
57
60
  time.sleep(delay)
61
+ protocol = "https" if use_ssl else "http"
58
62
  url = (
59
- f"http://127.0.0.1:{port}" if host == "0.0.0.0" else f"http://{host}:{port}"
63
+ f"{protocol}://127.0.0.1:{port}"
64
+ if host == "0.0.0.0"
65
+ else f"{protocol}://{host}:{port}"
60
66
  )
61
67
  try:
62
68
  webbrowser.open(url)
@@ -125,6 +131,16 @@ def main() -> None:
125
131
  action="store_true",
126
132
  help="Disable file logging",
127
133
  )
134
+ parser.add_argument(
135
+ "--ssl-keyfile",
136
+ default=None,
137
+ help="SSL key file path (for HTTPS)",
138
+ )
139
+ parser.add_argument(
140
+ "--ssl-certfile",
141
+ default=None,
142
+ help="SSL certificate file path (for HTTPS)",
143
+ )
128
144
 
129
145
  args = parser.parse_args()
130
146
 
@@ -172,6 +188,9 @@ def main() -> None:
172
188
  # 获取配置来源
173
189
  config_source = config_manager.get_config_source()
174
190
 
191
+ # Determine if SSL is enabled
192
+ use_ssl = args.ssl_keyfile is not None and args.ssl_certfile is not None
193
+
175
194
  # Display startup banner
176
195
  print()
177
196
  print("=" * 50)
@@ -179,7 +198,8 @@ def main() -> None:
179
198
  print("=" * 50)
180
199
  print(f" Version: {__version__}")
181
200
  print()
182
- print(f" Server: http://{args.host}:{args.port}")
201
+ protocol = "https" if use_ssl else "http"
202
+ print(f" Server: {protocol}://{args.host}:{args.port}")
183
203
  print()
184
204
  print(" Model Configuration:")
185
205
  print(f" Source: {config_source.value}")
@@ -202,13 +222,15 @@ def main() -> None:
202
222
 
203
223
  # Open browser automatically unless disabled
204
224
  if not args.no_browser:
205
- open_browser(args.host, args.port)
225
+ open_browser(args.host, args.port, use_ssl=use_ssl)
206
226
 
207
227
  uvicorn.run(
208
228
  server.app if not args.reload else "AutoGLM_GUI.server:app",
209
229
  host=args.host,
210
230
  port=args.port,
211
231
  reload=args.reload,
232
+ ssl_keyfile=args.ssl_keyfile,
233
+ ssl_certfile=args.ssl_certfile,
212
234
  )
213
235
 
214
236
 
@@ -0,0 +1,6 @@
1
+ """Action system for executing phone operations."""
2
+
3
+ from .handler import ActionHandler
4
+ from .types import ActionResult
5
+
6
+ __all__ = ["ActionHandler", "ActionResult"]
@@ -1,69 +1,27 @@
1
- """Action handler for iOS automation using WebDriverAgent."""
1
+ """Action handler for executing phone operations."""
2
2
 
3
3
  import time
4
- from dataclasses import dataclass
5
4
  from typing import Any, Callable
6
5
 
7
- from phone_agent.xctest import (
8
- back,
9
- double_tap,
10
- home,
11
- launch_app,
12
- long_press,
13
- swipe,
14
- tap,
15
- )
16
- from phone_agent.xctest.input import clear_text, hide_keyboard, type_text
6
+ from AutoGLM_GUI.device_protocol import DeviceProtocol
17
7
 
8
+ from .types import ActionResult
18
9
 
19
- @dataclass
20
- class ActionResult:
21
- """Result of an action execution."""
22
-
23
- success: bool
24
- should_finish: bool
25
- message: str | None = None
26
- requires_confirmation: bool = False
27
-
28
-
29
- class IOSActionHandler:
30
- """
31
- Handles execution of actions from AI model output for iOS devices.
32
-
33
- Args:
34
- wda_url: WebDriverAgent URL.
35
- session_id: Optional WDA session ID.
36
- confirmation_callback: Optional callback for sensitive action confirmation.
37
- Should return True to proceed, False to cancel.
38
- takeover_callback: Optional callback for takeover requests (login, captcha).
39
- """
40
10
 
11
+ class ActionHandler:
41
12
  def __init__(
42
13
  self,
43
- wda_url: str = "http://localhost:8100",
44
- session_id: str | None = None,
14
+ device: DeviceProtocol,
45
15
  confirmation_callback: Callable[[str], bool] | None = None,
46
16
  takeover_callback: Callable[[str], None] | None = None,
47
17
  ):
48
- self.wda_url = wda_url
49
- self.session_id = session_id
18
+ self.device = device
50
19
  self.confirmation_callback = confirmation_callback or self._default_confirmation
51
20
  self.takeover_callback = takeover_callback or self._default_takeover
52
21
 
53
22
  def execute(
54
23
  self, action: dict[str, Any], screen_width: int, screen_height: int
55
24
  ) -> ActionResult:
56
- """
57
- Execute an action from the AI model.
58
-
59
- Args:
60
- action: The action dictionary from the model.
61
- screen_width: Current screen width in pixels.
62
- screen_height: Current screen height in pixels.
63
-
64
- Returns:
65
- ActionResult indicating success and whether to finish.
66
- """
67
25
  action_type = action.get("_metadata")
68
26
 
69
27
  if action_type == "finish":
@@ -79,6 +37,13 @@ class IOSActionHandler:
79
37
  )
80
38
 
81
39
  action_name = action.get("action")
40
+ if not isinstance(action_name, str) or not action_name:
41
+ return ActionResult(
42
+ success=False,
43
+ should_finish=False,
44
+ message=f"Unknown action: {action_name}",
45
+ )
46
+
82
47
  handler_method = self._get_handler(action_name)
83
48
 
84
49
  if handler_method is None:
@@ -96,7 +61,6 @@ class IOSActionHandler:
96
61
  )
97
62
 
98
63
  def _get_handler(self, action_name: str) -> Callable | None:
99
- """Get the handler method for an action."""
100
64
  handlers = {
101
65
  "Launch": self._handle_launch,
102
66
  "Tap": self._handle_tap,
@@ -110,41 +74,33 @@ class IOSActionHandler:
110
74
  "Wait": self._handle_wait,
111
75
  "Take_over": self._handle_takeover,
112
76
  "Note": self._handle_note,
113
- "Call_API": self._handle_call_api,
114
- "Interact": self._handle_interact,
115
77
  }
116
78
  return handlers.get(action_name)
117
79
 
118
80
  def _convert_relative_to_absolute(
119
81
  self, element: list[int], screen_width: int, screen_height: int
120
82
  ) -> tuple[int, int]:
121
- """Convert relative coordinates (0-1000) to absolute pixels."""
122
83
  x = int(element[0] / 1000 * screen_width)
123
84
  y = int(element[1] / 1000 * screen_height)
124
85
  return x, y
125
86
 
126
87
  def _handle_launch(self, action: dict, width: int, height: int) -> ActionResult:
127
- """Handle app launch action."""
128
88
  app_name = action.get("app")
129
89
  if not app_name:
130
90
  return ActionResult(False, False, "No app name specified")
131
91
 
132
- success = launch_app(app_name, wda_url=self.wda_url, session_id=self.session_id)
92
+ success = self.device.launch_app(app_name)
133
93
  if success:
134
94
  return ActionResult(True, False)
135
95
  return ActionResult(False, False, f"App not found: {app_name}")
136
96
 
137
97
  def _handle_tap(self, action: dict, width: int, height: int) -> ActionResult:
138
- """Handle tap action."""
139
98
  element = action.get("element")
140
99
  if not element:
141
100
  return ActionResult(False, False, "No element coordinates")
142
101
 
143
102
  x, y = self._convert_relative_to_absolute(element, width, height)
144
103
 
145
- print(f"Physically tap on ({x}, {y})")
146
-
147
- # Check for sensitive operation
148
104
  if "message" in action:
149
105
  if not self.confirmation_callback(action["message"]):
150
106
  return ActionResult(
@@ -153,28 +109,27 @@ class IOSActionHandler:
153
109
  message="User cancelled sensitive operation",
154
110
  )
155
111
 
156
- tap(x, y, wda_url=self.wda_url, session_id=self.session_id)
112
+ self.device.tap(x, y)
157
113
  return ActionResult(True, False)
158
114
 
159
115
  def _handle_type(self, action: dict, width: int, height: int) -> ActionResult:
160
- """Handle text input action."""
161
116
  text = action.get("text", "")
162
117
 
163
- # Clear existing text and type new text
164
- clear_text(wda_url=self.wda_url, session_id=self.session_id)
118
+ original_ime = self.device.detect_and_set_adb_keyboard()
165
119
  time.sleep(0.5)
166
120
 
167
- type_text(text, wda_url=self.wda_url, session_id=self.session_id)
168
- time.sleep(0.5)
121
+ self.device.clear_text()
122
+ time.sleep(0.3)
169
123
 
170
- # Hide keyboard after typing
171
- hide_keyboard(wda_url=self.wda_url, session_id=self.session_id)
124
+ self.device.type_text(text)
172
125
  time.sleep(0.5)
173
126
 
127
+ self.device.restore_keyboard(original_ime)
128
+ time.sleep(0.3)
129
+
174
130
  return ActionResult(True, False)
175
131
 
176
132
  def _handle_swipe(self, action: dict, width: int, height: int) -> ActionResult:
177
- """Handle swipe action."""
178
133
  start = action.get("start")
179
134
  end = action.get("end")
180
135
 
@@ -184,56 +139,36 @@ class IOSActionHandler:
184
139
  start_x, start_y = self._convert_relative_to_absolute(start, width, height)
185
140
  end_x, end_y = self._convert_relative_to_absolute(end, width, height)
186
141
 
187
- print(f"Physically scroll from ({start_x}, {start_y}) to ({end_x}, {end_y})")
188
-
189
- swipe(
190
- start_x,
191
- start_y,
192
- end_x,
193
- end_y,
194
- wda_url=self.wda_url,
195
- session_id=self.session_id,
196
- )
142
+ self.device.swipe(start_x, start_y, end_x, end_y)
197
143
  return ActionResult(True, False)
198
144
 
199
145
  def _handle_back(self, action: dict, width: int, height: int) -> ActionResult:
200
- """Handle back gesture (swipe from left edge)."""
201
- back(wda_url=self.wda_url, session_id=self.session_id)
146
+ self.device.back()
202
147
  return ActionResult(True, False)
203
148
 
204
149
  def _handle_home(self, action: dict, width: int, height: int) -> ActionResult:
205
- """Handle home button action."""
206
- home(wda_url=self.wda_url, session_id=self.session_id)
150
+ self.device.home()
207
151
  return ActionResult(True, False)
208
152
 
209
153
  def _handle_double_tap(self, action: dict, width: int, height: int) -> ActionResult:
210
- """Handle double tap action."""
211
154
  element = action.get("element")
212
155
  if not element:
213
156
  return ActionResult(False, False, "No element coordinates")
214
157
 
215
158
  x, y = self._convert_relative_to_absolute(element, width, height)
216
- double_tap(x, y, wda_url=self.wda_url, session_id=self.session_id)
159
+ self.device.double_tap(x, y)
217
160
  return ActionResult(True, False)
218
161
 
219
162
  def _handle_long_press(self, action: dict, width: int, height: int) -> ActionResult:
220
- """Handle long press action."""
221
163
  element = action.get("element")
222
164
  if not element:
223
165
  return ActionResult(False, False, "No element coordinates")
224
166
 
225
167
  x, y = self._convert_relative_to_absolute(element, width, height)
226
- long_press(
227
- x,
228
- y,
229
- duration=3.0,
230
- wda_url=self.wda_url,
231
- session_id=self.session_id,
232
- )
168
+ self.device.long_press(x, y)
233
169
  return ActionResult(True, False)
234
170
 
235
171
  def _handle_wait(self, action: dict, width: int, height: int) -> ActionResult:
236
- """Handle wait action."""
237
172
  duration_str = action.get("duration", "1 seconds")
238
173
  try:
239
174
  duration = float(duration_str.replace("seconds", "").strip())
@@ -244,35 +179,18 @@ class IOSActionHandler:
244
179
  return ActionResult(True, False)
245
180
 
246
181
  def _handle_takeover(self, action: dict, width: int, height: int) -> ActionResult:
247
- """Handle takeover request (login, captcha, etc.)."""
248
182
  message = action.get("message", "User intervention required")
249
183
  self.takeover_callback(message)
250
184
  return ActionResult(True, False)
251
185
 
252
186
  def _handle_note(self, action: dict, width: int, height: int) -> ActionResult:
253
- """Handle note action (placeholder for content recording)."""
254
- # This action is typically used for recording page content
255
- # Implementation depends on specific requirements
256
- return ActionResult(True, False)
257
-
258
- def _handle_call_api(self, action: dict, width: int, height: int) -> ActionResult:
259
- """Handle API call action (placeholder for summarization)."""
260
- # This action is typically used for content summarization
261
- # Implementation depends on specific requirements
262
187
  return ActionResult(True, False)
263
188
 
264
- def _handle_interact(self, action: dict, width: int, height: int) -> ActionResult:
265
- """Handle interaction request (user choice needed)."""
266
- # This action signals that user input is needed
267
- return ActionResult(True, False, message="User interaction required")
268
-
269
189
  @staticmethod
270
190
  def _default_confirmation(message: str) -> bool:
271
- """Default confirmation callback using console input."""
272
- response = input(f"Sensitive operation: {message}\nConfirm? (Y/N): ")
273
- return response.upper() == "Y"
191
+ response = input(f"\n⚠️ Confirm action: {message} (y/n): ")
192
+ return response.lower() in ("y", "yes")
274
193
 
275
194
  @staticmethod
276
195
  def _default_takeover(message: str) -> None:
277
- """Default takeover callback using console input."""
278
- input(f"{message}\nPress Enter after completing manual operation...")
196
+ input(f"\n🤚 {message}. Press Enter to continue...")
@@ -0,0 +1,15 @@
1
+ """Type definitions for actions."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+
7
+ @dataclass
8
+ class ActionResult:
9
+ success: bool
10
+ should_finish: bool
11
+ message: str | None = None
12
+ requires_confirmation: bool = False
13
+
14
+
15
+ Action = dict[str, Any]
@@ -1,13 +1,12 @@
1
- """ADB utilities for Android device interaction."""
2
-
3
- from phone_agent.adb.connection import (
1
+ from AutoGLM_GUI.adb.apps import APP_PACKAGES, get_app_name, get_package_name
2
+ from AutoGLM_GUI.adb.connection import (
4
3
  ADBConnection,
5
4
  ConnectionType,
6
5
  DeviceInfo,
7
6
  list_devices,
8
7
  quick_connect,
9
8
  )
10
- from phone_agent.adb.device import (
9
+ from AutoGLM_GUI.adb.device import (
11
10
  back,
12
11
  double_tap,
13
12
  get_current_app,
@@ -17,35 +16,38 @@ from phone_agent.adb.device import (
17
16
  swipe,
18
17
  tap,
19
18
  )
20
- from phone_agent.adb.input import (
19
+ from AutoGLM_GUI.adb.input import (
21
20
  clear_text,
22
21
  detect_and_set_adb_keyboard,
23
22
  restore_keyboard,
24
23
  type_text,
25
24
  )
26
- from phone_agent.adb.screenshot import get_screenshot
25
+ from AutoGLM_GUI.adb.screenshot import Screenshot, get_screenshot
26
+ from AutoGLM_GUI.adb.timing import TIMING_CONFIG, TimingConfig
27
27
 
28
28
  __all__ = [
29
- # Screenshot
30
- "get_screenshot",
31
- # Input
32
- "type_text",
33
- "clear_text",
34
- "detect_and_set_adb_keyboard",
35
- "restore_keyboard",
36
- # Device control
37
- "get_current_app",
29
+ "ADBConnection",
30
+ "ConnectionType",
31
+ "DeviceInfo",
32
+ "list_devices",
33
+ "quick_connect",
34
+ "TIMING_CONFIG",
35
+ "TimingConfig",
36
+ "APP_PACKAGES",
37
+ "get_package_name",
38
+ "get_app_name",
38
39
  "tap",
40
+ "double_tap",
41
+ "long_press",
39
42
  "swipe",
40
43
  "back",
41
44
  "home",
42
- "double_tap",
43
- "long_press",
44
45
  "launch_app",
45
- # Connection management
46
- "ADBConnection",
47
- "DeviceInfo",
48
- "ConnectionType",
49
- "quick_connect",
50
- "list_devices",
46
+ "get_current_app",
47
+ "type_text",
48
+ "clear_text",
49
+ "detect_and_set_adb_keyboard",
50
+ "restore_keyboard",
51
+ "Screenshot",
52
+ "get_screenshot",
51
53
  ]
@@ -5,7 +5,8 @@ import time
5
5
  from dataclasses import dataclass
6
6
  from enum import Enum
7
7
 
8
- from phone_agent.config.timing import TIMING_CONFIG
8
+ from AutoGLM_GUI.adb.timing import TIMING_CONFIG
9
+ from AutoGLM_GUI.adb_plus.ip import get_wifi_ip
9
10
 
10
11
 
11
12
  class ConnectionType(Enum):
@@ -261,51 +262,15 @@ class ADBConnection:
261
262
  """
262
263
  Get the IP address of a connected device.
263
264
 
265
+ Delegates to adb_plus.ip.get_wifi_ip() for better WiFi interface detection.
266
+
264
267
  Args:
265
268
  device_id: Device ID. If None, uses first available device.
266
269
 
267
270
  Returns:
268
271
  IP address string or None if not found.
269
272
  """
270
- try:
271
- cmd = [self.adb_path]
272
- if device_id:
273
- cmd.extend(["-s", device_id])
274
- cmd.extend(["shell", "ip", "route"])
275
-
276
- result = subprocess.run(
277
- cmd, capture_output=True, text=True, encoding="utf-8", timeout=5
278
- )
279
-
280
- # Parse IP from route output
281
- for line in result.stdout.split("\n"):
282
- if "src" in line:
283
- parts = line.split()
284
- for i, part in enumerate(parts):
285
- if part == "src" and i + 1 < len(parts):
286
- return parts[i + 1]
287
-
288
- # Alternative: try wlan0 interface
289
- cmd[-1] = "ip addr show wlan0"
290
- result = subprocess.run(
291
- cmd[:-1] + ["shell", "ip", "addr", "show", "wlan0"],
292
- capture_output=True,
293
- text=True,
294
- encoding="utf-8",
295
- timeout=5,
296
- )
297
-
298
- for line in result.stdout.split("\n"):
299
- if "inet " in line:
300
- parts = line.strip().split()
301
- if len(parts) >= 2:
302
- return parts[1].split("/")[0]
303
-
304
- return None
305
-
306
- except Exception as e:
307
- print(f"Error getting device IP: {e}")
308
- return None
273
+ return get_wifi_ip(adb_path=self.adb_path, device_id=device_id)
309
274
 
310
275
  def restart_server(self) -> tuple[bool, str]:
311
276
  """