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.
- AutoGLM_GUI/__init__.py +11 -0
- AutoGLM_GUI/__main__.py +26 -8
- 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/qr_pair.py +8 -8
- 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 +51 -0
- AutoGLM_GUI/agents/events.py +19 -0
- AutoGLM_GUI/agents/factory.py +153 -0
- 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 +27 -0
- AutoGLM_GUI/agents/stream_runner.py +188 -0
- AutoGLM_GUI/api/__init__.py +71 -11
- AutoGLM_GUI/api/agents.py +190 -229
- AutoGLM_GUI/api/control.py +9 -6
- AutoGLM_GUI/api/devices.py +112 -28
- AutoGLM_GUI/api/health.py +13 -0
- AutoGLM_GUI/api/history.py +78 -0
- AutoGLM_GUI/api/layered_agent.py +306 -181
- AutoGLM_GUI/api/mcp.py +11 -10
- AutoGLM_GUI/api/media.py +64 -1
- AutoGLM_GUI/api/scheduled_tasks.py +98 -0
- AutoGLM_GUI/api/version.py +23 -10
- AutoGLM_GUI/api/workflows.py +2 -1
- AutoGLM_GUI/config.py +72 -14
- AutoGLM_GUI/config_manager.py +98 -27
- AutoGLM_GUI/device_adapter.py +263 -0
- AutoGLM_GUI/device_manager.py +248 -29
- AutoGLM_GUI/device_protocol.py +266 -0
- AutoGLM_GUI/devices/__init__.py +49 -0
- AutoGLM_GUI/devices/adb_device.py +200 -0
- AutoGLM_GUI/devices/mock_device.py +185 -0
- AutoGLM_GUI/devices/remote_device.py +177 -0
- AutoGLM_GUI/exceptions.py +3 -3
- AutoGLM_GUI/history_manager.py +164 -0
- AutoGLM_GUI/i18n.py +81 -0
- AutoGLM_GUI/metrics.py +13 -20
- 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 +118 -367
- AutoGLM_GUI/platform_utils.py +31 -2
- 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 +272 -63
- AutoGLM_GUI/scrcpy_stream.py +159 -37
- AutoGLM_GUI/server.py +3 -1
- AutoGLM_GUI/socketio_server.py +114 -29
- AutoGLM_GUI/state.py +10 -30
- AutoGLM_GUI/static/assets/{about-DeclntHg.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-zQ4KKDHt.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 +142 -0
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/METADATA +178 -92
- autoglm_gui-1.5.0.dist-info/RECORD +157 -0
- mai_agent/base.py +137 -0
- mai_agent/mai_grounding_agent.py +263 -0
- mai_agent/mai_naivigation_agent.py +526 -0
- mai_agent/prompt.py +148 -0
- mai_agent/unified_memory.py +67 -0
- mai_agent/utils.py +73 -0
- AutoGLM_GUI/api/dual_model.py +0 -311
- 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 -146
- AutoGLM_GUI/static/assets/chat-Iut2yhSw.js +0 -125
- AutoGLM_GUI/static/assets/dialog-BfdcBs1x.js +0 -45
- AutoGLM_GUI/static/assets/index-5hCCwHA7.css +0 -1
- AutoGLM_GUI/static/assets/index-DHF1NZh0.js +0 -12
- AutoGLM_GUI/static/assets/workflows-xiplap-r.js +0 -1
- autoglm_gui-1.4.0.dist-info/RECORD +0 -100
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/WHEEL +0 -0
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/entry_points.txt +0 -0
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/licenses/LICENSE +0 -0
AutoGLM_GUI/api/devices.py
CHANGED
|
@@ -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
|
-
) ->
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
device: ManagedDevice 实例
|
|
41
|
-
agent_manager: PhoneAgentManager 实例
|
|
43
|
+
device: "ManagedDevice", agent_manager: "PhoneAgentManager"
|
|
44
|
+
) -> DeviceResponse:
|
|
45
|
+
"""聚合设备信息和 Agent 状态(API 层职责).
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
API 层负责协调 DeviceManager 和 PhoneAgentManager,
|
|
48
|
+
通过遍历设备的所有连接来查找已初始化的 Agent。
|
|
45
49
|
"""
|
|
46
|
-
# 获取纯设备信息
|
|
47
|
-
response = device.to_dict()
|
|
48
50
|
|
|
49
|
-
|
|
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
|
|
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
|
-
|
|
64
|
-
|
|
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
|
|
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
|
|
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}"}
|