autoglm-gui 1.4.0__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.
Files changed (120) hide show
  1. AutoGLM_GUI/__init__.py +11 -0
  2. AutoGLM_GUI/__main__.py +26 -8
  3. AutoGLM_GUI/actions/__init__.py +6 -0
  4. AutoGLM_GUI/actions/handler.py +196 -0
  5. AutoGLM_GUI/actions/types.py +15 -0
  6. AutoGLM_GUI/adb/__init__.py +53 -0
  7. AutoGLM_GUI/adb/apps.py +227 -0
  8. AutoGLM_GUI/adb/connection.py +323 -0
  9. AutoGLM_GUI/adb/device.py +171 -0
  10. AutoGLM_GUI/adb/input.py +67 -0
  11. AutoGLM_GUI/adb/screenshot.py +11 -0
  12. AutoGLM_GUI/adb/timing.py +167 -0
  13. AutoGLM_GUI/adb_plus/keyboard_installer.py +4 -2
  14. AutoGLM_GUI/adb_plus/qr_pair.py +8 -8
  15. AutoGLM_GUI/adb_plus/screenshot.py +22 -1
  16. AutoGLM_GUI/adb_plus/serial.py +38 -20
  17. AutoGLM_GUI/adb_plus/touch.py +4 -9
  18. AutoGLM_GUI/agents/__init__.py +51 -0
  19. AutoGLM_GUI/agents/events.py +19 -0
  20. AutoGLM_GUI/agents/factory.py +153 -0
  21. AutoGLM_GUI/agents/glm/__init__.py +7 -0
  22. AutoGLM_GUI/agents/glm/agent.py +292 -0
  23. AutoGLM_GUI/agents/glm/message_builder.py +81 -0
  24. AutoGLM_GUI/agents/glm/parser.py +110 -0
  25. AutoGLM_GUI/agents/glm/prompts_en.py +77 -0
  26. AutoGLM_GUI/agents/glm/prompts_zh.py +75 -0
  27. AutoGLM_GUI/agents/mai/__init__.py +28 -0
  28. AutoGLM_GUI/agents/mai/agent.py +405 -0
  29. AutoGLM_GUI/agents/mai/parser.py +254 -0
  30. AutoGLM_GUI/agents/mai/prompts.py +103 -0
  31. AutoGLM_GUI/agents/mai/traj_memory.py +91 -0
  32. AutoGLM_GUI/agents/protocols.py +27 -0
  33. AutoGLM_GUI/agents/stream_runner.py +188 -0
  34. AutoGLM_GUI/api/__init__.py +71 -11
  35. AutoGLM_GUI/api/agents.py +190 -229
  36. AutoGLM_GUI/api/control.py +9 -6
  37. AutoGLM_GUI/api/devices.py +112 -28
  38. AutoGLM_GUI/api/health.py +13 -0
  39. AutoGLM_GUI/api/history.py +78 -0
  40. AutoGLM_GUI/api/layered_agent.py +306 -181
  41. AutoGLM_GUI/api/mcp.py +11 -10
  42. AutoGLM_GUI/api/media.py +64 -1
  43. AutoGLM_GUI/api/scheduled_tasks.py +98 -0
  44. AutoGLM_GUI/api/version.py +23 -10
  45. AutoGLM_GUI/api/workflows.py +2 -1
  46. AutoGLM_GUI/config.py +72 -14
  47. AutoGLM_GUI/config_manager.py +98 -27
  48. AutoGLM_GUI/device_adapter.py +263 -0
  49. AutoGLM_GUI/device_manager.py +248 -29
  50. AutoGLM_GUI/device_protocol.py +266 -0
  51. AutoGLM_GUI/devices/__init__.py +49 -0
  52. AutoGLM_GUI/devices/adb_device.py +200 -0
  53. AutoGLM_GUI/devices/mock_device.py +185 -0
  54. AutoGLM_GUI/devices/remote_device.py +177 -0
  55. AutoGLM_GUI/exceptions.py +3 -3
  56. AutoGLM_GUI/history_manager.py +164 -0
  57. AutoGLM_GUI/i18n.py +81 -0
  58. AutoGLM_GUI/metrics.py +13 -20
  59. AutoGLM_GUI/model/__init__.py +5 -0
  60. AutoGLM_GUI/model/message_builder.py +69 -0
  61. AutoGLM_GUI/model/types.py +24 -0
  62. AutoGLM_GUI/models/__init__.py +10 -0
  63. AutoGLM_GUI/models/history.py +96 -0
  64. AutoGLM_GUI/models/scheduled_task.py +71 -0
  65. AutoGLM_GUI/parsers/__init__.py +22 -0
  66. AutoGLM_GUI/parsers/base.py +50 -0
  67. AutoGLM_GUI/parsers/phone_parser.py +58 -0
  68. AutoGLM_GUI/phone_agent_manager.py +118 -367
  69. AutoGLM_GUI/platform_utils.py +31 -2
  70. AutoGLM_GUI/prompt_config.py +15 -0
  71. AutoGLM_GUI/prompts/__init__.py +32 -0
  72. AutoGLM_GUI/scheduler_manager.py +304 -0
  73. AutoGLM_GUI/schemas.py +272 -63
  74. AutoGLM_GUI/scrcpy_stream.py +159 -37
  75. AutoGLM_GUI/server.py +3 -1
  76. AutoGLM_GUI/socketio_server.py +114 -29
  77. AutoGLM_GUI/state.py +10 -30
  78. AutoGLM_GUI/static/assets/{about-DeclntHg.js → about-BQm96DAl.js} +1 -1
  79. AutoGLM_GUI/static/assets/alert-dialog-B42XxGPR.js +1 -0
  80. AutoGLM_GUI/static/assets/chat-C0L2gQYG.js +129 -0
  81. AutoGLM_GUI/static/assets/circle-alert-D4rSJh37.js +1 -0
  82. AutoGLM_GUI/static/assets/dialog-DZ78cEcj.js +45 -0
  83. AutoGLM_GUI/static/assets/history-DFBv7TGc.js +1 -0
  84. AutoGLM_GUI/static/assets/index-Bzyv2yQ2.css +1 -0
  85. AutoGLM_GUI/static/assets/{index-zQ4KKDHt.js → index-CmZSnDqc.js} +1 -1
  86. AutoGLM_GUI/static/assets/index-CssG-3TH.js +11 -0
  87. AutoGLM_GUI/static/assets/label-BCUzE_nm.js +1 -0
  88. AutoGLM_GUI/static/assets/logs-eoFxn5of.js +1 -0
  89. AutoGLM_GUI/static/assets/popover-DLsuV5Sx.js +1 -0
  90. AutoGLM_GUI/static/assets/scheduled-tasks-MyqGJvy_.js +1 -0
  91. AutoGLM_GUI/static/assets/square-pen-zGWYrdfj.js +1 -0
  92. AutoGLM_GUI/static/assets/textarea-BX6y7uM5.js +1 -0
  93. AutoGLM_GUI/static/assets/workflows-CYFs6ssC.js +1 -0
  94. AutoGLM_GUI/static/index.html +2 -2
  95. AutoGLM_GUI/types.py +142 -0
  96. {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/METADATA +178 -92
  97. autoglm_gui-1.5.0.dist-info/RECORD +157 -0
  98. mai_agent/base.py +137 -0
  99. mai_agent/mai_grounding_agent.py +263 -0
  100. mai_agent/mai_naivigation_agent.py +526 -0
  101. mai_agent/prompt.py +148 -0
  102. mai_agent/unified_memory.py +67 -0
  103. mai_agent/utils.py +73 -0
  104. AutoGLM_GUI/api/dual_model.py +0 -311
  105. AutoGLM_GUI/dual_model/__init__.py +0 -53
  106. AutoGLM_GUI/dual_model/decision_model.py +0 -664
  107. AutoGLM_GUI/dual_model/dual_agent.py +0 -917
  108. AutoGLM_GUI/dual_model/protocols.py +0 -354
  109. AutoGLM_GUI/dual_model/vision_model.py +0 -442
  110. AutoGLM_GUI/mai_ui_adapter/agent_wrapper.py +0 -291
  111. AutoGLM_GUI/phone_agent_patches.py +0 -146
  112. AutoGLM_GUI/static/assets/chat-Iut2yhSw.js +0 -125
  113. AutoGLM_GUI/static/assets/dialog-BfdcBs1x.js +0 -45
  114. AutoGLM_GUI/static/assets/index-5hCCwHA7.css +0 -1
  115. AutoGLM_GUI/static/assets/index-DHF1NZh0.js +0 -12
  116. AutoGLM_GUI/static/assets/workflows-xiplap-r.js +0 -1
  117. autoglm_gui-1.4.0.dist-info/RECORD +0 -100
  118. {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/WHEEL +0 -0
  119. {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/entry_points.txt +0 -0
  120. {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -15,6 +15,19 @@ from AutoGLM_GUI.logger import logger
15
15
 
16
16
  from AutoGLM_GUI.schemas import (
17
17
  DeviceListResponse,
18
+ DeviceResponse,
19
+ MdnsDeviceResponse,
20
+ MdnsDiscoverResponse,
21
+ QRPairCancelResponse,
22
+ QRPairGenerateResponse,
23
+ QRPairStatusResponse,
24
+ RemoteDeviceAddRequest,
25
+ RemoteDeviceAddResponse,
26
+ RemoteDeviceDiscoverRequest,
27
+ RemoteDeviceDiscoverResponse,
28
+ RemoteDeviceInfo,
29
+ RemoteDeviceRemoveRequest,
30
+ RemoteDeviceRemoveResponse,
18
31
  WiFiConnectRequest,
19
32
  WiFiConnectResponse,
20
33
  WiFiDisconnectRequest,
@@ -23,49 +36,41 @@ from AutoGLM_GUI.schemas import (
23
36
  WiFiManualConnectResponse,
24
37
  WiFiPairRequest,
25
38
  WiFiPairResponse,
26
- MdnsDiscoverResponse,
27
- MdnsDeviceResponse,
28
- QRPairGenerateResponse,
29
- QRPairStatusResponse,
30
- QRPairCancelResponse,
31
39
  )
32
40
 
33
41
 
34
42
  def _build_device_response_with_agent(
35
- device: ManagedDevice, agent_manager: PhoneAgentManager
36
- ) -> dict:
37
- """组合设备信息和 Agent 状态(API 层职责)。
38
-
39
- Args:
40
- device: ManagedDevice 实例
41
- agent_manager: PhoneAgentManager 实例
43
+ device: "ManagedDevice", agent_manager: "PhoneAgentManager"
44
+ ) -> DeviceResponse:
45
+ """聚合设备信息和 Agent 状态(API 层职责).
42
46
 
43
- Returns:
44
- dict: 完整的设备响应,匹配 DeviceResponse schema
47
+ API 层负责协调 DeviceManager 和 PhoneAgentManager,
48
+ 通过遍历设备的所有连接来查找已初始化的 Agent。
45
49
  """
46
- # 获取纯设备信息
47
- response = device.to_dict()
48
50
 
49
- # 通过 serial 查找 Agent(支持连接切换)
50
- agent_device_id = agent_manager.find_agent_by_serial(device.serial)
51
-
52
- if agent_device_id:
53
- metadata = agent_manager.get_metadata(agent_device_id)
51
+ response = device.to_dict()
54
52
 
53
+ # 遍历设备的所有连接,查找已初始化的 Agent
54
+ # 使用 device.connections 公开属性(ManagedDevice 提供)
55
+ for conn in device.connections:
56
+ # 只调用 PhoneAgentManager 的公开方法
57
+ metadata = agent_manager.get_metadata(conn.device_id)
55
58
  if metadata:
59
+ # 找到了已初始化的 Agent
56
60
  response["agent"] = {
57
- "state": metadata.state.value,
61
+ "state": metadata.state, # AgentState is str, Enum, already a string
58
62
  "created_at": metadata.created_at,
59
63
  "last_used": metadata.last_used,
60
64
  "error_message": metadata.error_message,
61
65
  "model_name": metadata.model_config.model_name,
62
66
  }
63
- else:
64
- response["agent"] = None
67
+
68
+ break # 找到第一个 Agent 即可退出
65
69
  else:
70
+ # 没有找到任何已初始化的 Agent
66
71
  response["agent"] = None
67
72
 
68
- return response
73
+ return DeviceResponse.model_validate(response)
69
74
 
70
75
 
71
76
  router = APIRouter()
@@ -97,9 +102,15 @@ def list_devices() -> DeviceListResponse:
97
102
 
98
103
  @router.post("/api/devices/connect_wifi", response_model=WiFiConnectResponse)
99
104
  def connect_wifi(request: WiFiConnectRequest) -> WiFiConnectResponse:
100
- """从 USB 启用 TCP/IP 并连接到 WiFi。"""
101
105
  from AutoGLM_GUI.device_manager import DeviceManager
102
106
 
107
+ if not request.device_id:
108
+ return WiFiConnectResponse(
109
+ success=False,
110
+ message="device_id is required",
111
+ error="device_not_found",
112
+ )
113
+
103
114
  device_manager = DeviceManager.get_instance()
104
115
  success, message, wifi_id = device_manager.connect_wifi(
105
116
  device_id=request.device_id,
@@ -235,7 +246,7 @@ def pair_wifi(request: WiFiPairRequest) -> WiFiPairResponse:
235
246
  @router.get("/api/devices/discover_mdns", response_model=MdnsDiscoverResponse)
236
247
  def discover_mdns() -> MdnsDiscoverResponse:
237
248
  """Discover wireless ADB devices via mDNS."""
238
- from phone_agent.adb import ADBConnection
249
+ from AutoGLM_GUI.adb import ADBConnection
239
250
  from AutoGLM_GUI.adb_plus import discover_mdns_devices
240
251
 
241
252
  try:
@@ -281,7 +292,7 @@ def generate_qr_pairing(timeout: int = 90) -> QRPairGenerateResponse:
281
292
  QR code payload and session information
282
293
  """
283
294
  try:
284
- from phone_agent.adb import ADBConnection
295
+ from AutoGLM_GUI.adb import ADBConnection
285
296
 
286
297
  conn = ADBConnection()
287
298
  session = qr_pairing_manager.create_session(
@@ -370,3 +381,76 @@ def cancel_qr_pairing(session_id: str) -> QRPairCancelResponse:
370
381
  success=False,
371
382
  message="Session not found or already completed",
372
383
  )
384
+
385
+
386
+ @router.post(
387
+ "/api/devices/discover_remote", response_model=RemoteDeviceDiscoverResponse
388
+ )
389
+ def discover_remote_devices(
390
+ request: RemoteDeviceDiscoverRequest,
391
+ ) -> RemoteDeviceDiscoverResponse:
392
+ """Discover devices from a remote Device Agent Server."""
393
+ from AutoGLM_GUI.device_manager import DeviceManager
394
+
395
+ device_manager = DeviceManager.get_instance()
396
+ success, message, devices_list = device_manager.discover_remote_devices(
397
+ base_url=request.base_url,
398
+ timeout=request.timeout,
399
+ )
400
+
401
+ devices = [RemoteDeviceInfo(**d) for d in devices_list]
402
+
403
+ return RemoteDeviceDiscoverResponse(
404
+ success=success,
405
+ devices=devices,
406
+ message=message,
407
+ error=None if success else message,
408
+ )
409
+
410
+
411
+ @router.post("/api/devices/add_remote", response_model=RemoteDeviceAddResponse)
412
+ def add_remote_device(request: RemoteDeviceAddRequest) -> RemoteDeviceAddResponse:
413
+ """Add a remote HTTP proxy device manually."""
414
+ from AutoGLM_GUI.device_manager import DeviceManager
415
+
416
+ device_manager = DeviceManager.get_instance()
417
+ success, message, serial = device_manager.add_remote_device(
418
+ base_url=request.base_url,
419
+ device_id=request.device_id,
420
+ )
421
+
422
+ if success:
423
+ return RemoteDeviceAddResponse(
424
+ success=True,
425
+ message=message,
426
+ serial=serial,
427
+ )
428
+ else:
429
+ error_type = "add_failed"
430
+ if "already exists" in message.lower():
431
+ error_type = "already_exists"
432
+ elif "connection failed" in message.lower():
433
+ error_type = "connection_failed"
434
+
435
+ return RemoteDeviceAddResponse(
436
+ success=False,
437
+ message=message,
438
+ error=error_type,
439
+ )
440
+
441
+
442
+ @router.post("/api/devices/remove_remote", response_model=RemoteDeviceRemoveResponse)
443
+ def remove_remote_device(
444
+ request: RemoteDeviceRemoveRequest,
445
+ ) -> RemoteDeviceRemoveResponse:
446
+ """Remove a remote device."""
447
+ from AutoGLM_GUI.device_manager import DeviceManager
448
+
449
+ device_manager = DeviceManager.get_instance()
450
+ success, message = device_manager.remove_remote_device(request.serial)
451
+
452
+ return RemoteDeviceRemoveResponse(
453
+ success=success,
454
+ message=message,
455
+ error=None if success else "remove_failed",
456
+ )
@@ -0,0 +1,13 @@
1
+ from fastapi import APIRouter
2
+
3
+ from AutoGLM_GUI.version import APP_VERSION
4
+
5
+ router = APIRouter(prefix="/api", tags=["health"])
6
+
7
+
8
+ @router.get("/health")
9
+ async def health_check() -> dict:
10
+ return {
11
+ "status": "healthy",
12
+ "version": APP_VERSION,
13
+ }
@@ -0,0 +1,78 @@
1
+ """History API routes."""
2
+
3
+ from fastapi import APIRouter, HTTPException
4
+
5
+ from AutoGLM_GUI.history_manager import history_manager
6
+ from AutoGLM_GUI.schemas import HistoryListResponse, HistoryRecordResponse
7
+
8
+ router = APIRouter()
9
+
10
+
11
+ @router.get("/api/history/{serialno}", response_model=HistoryListResponse)
12
+ def list_history(
13
+ serialno: str, limit: int = 50, offset: int = 0
14
+ ) -> HistoryListResponse:
15
+ if limit < 1 or limit > 100:
16
+ raise HTTPException(status_code=400, detail="limit must be between 1 and 100")
17
+ if offset < 0:
18
+ raise HTTPException(status_code=400, detail="offset must be non-negative")
19
+
20
+ records = history_manager.list_records(serialno, limit=limit, offset=offset)
21
+ total = history_manager.get_total_count(serialno)
22
+
23
+ return HistoryListResponse(
24
+ records=[
25
+ HistoryRecordResponse(
26
+ id=r.id,
27
+ task_text=r.task_text,
28
+ final_message=r.final_message,
29
+ success=r.success,
30
+ steps=r.steps,
31
+ start_time=r.start_time.isoformat(),
32
+ end_time=r.end_time.isoformat() if r.end_time else None,
33
+ duration_ms=r.duration_ms,
34
+ source=r.source,
35
+ source_detail=r.source_detail,
36
+ error_message=r.error_message,
37
+ )
38
+ for r in records
39
+ ],
40
+ total=total,
41
+ limit=limit,
42
+ offset=offset,
43
+ )
44
+
45
+
46
+ @router.get("/api/history/{serialno}/{record_id}", response_model=HistoryRecordResponse)
47
+ def get_history_record(serialno: str, record_id: str) -> HistoryRecordResponse:
48
+ record = history_manager.get_record(serialno, record_id)
49
+ if not record:
50
+ raise HTTPException(status_code=404, detail="Record not found")
51
+
52
+ return HistoryRecordResponse(
53
+ id=record.id,
54
+ task_text=record.task_text,
55
+ final_message=record.final_message,
56
+ success=record.success,
57
+ steps=record.steps,
58
+ start_time=record.start_time.isoformat(),
59
+ end_time=record.end_time.isoformat() if record.end_time else None,
60
+ duration_ms=record.duration_ms,
61
+ source=record.source,
62
+ source_detail=record.source_detail,
63
+ error_message=record.error_message,
64
+ )
65
+
66
+
67
+ @router.delete("/api/history/{serialno}/{record_id}")
68
+ def delete_history_record(serialno: str, record_id: str) -> dict:
69
+ success = history_manager.delete_record(serialno, record_id)
70
+ if not success:
71
+ raise HTTPException(status_code=404, detail="Record not found")
72
+ return {"success": True, "message": "Record deleted"}
73
+
74
+
75
+ @router.delete("/api/history/{serialno}")
76
+ def clear_history(serialno: str) -> dict:
77
+ history_manager.clear_device_history(serialno)
78
+ return {"success": True, "message": f"History cleared for {serialno}"}