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.
- AutoGLM_GUI/__init__.py +11 -0
- AutoGLM_GUI/__main__.py +26 -4
- AutoGLM_GUI/actions/__init__.py +6 -0
- phone_agent/actions/handler_ios.py → AutoGLM_GUI/actions/handler.py +30 -112
- AutoGLM_GUI/actions/types.py +15 -0
- {phone_agent → AutoGLM_GUI}/adb/__init__.py +25 -23
- {phone_agent → AutoGLM_GUI}/adb/connection.py +5 -40
- {phone_agent → AutoGLM_GUI}/adb/device.py +12 -94
- {phone_agent → AutoGLM_GUI}/adb/input.py +6 -47
- AutoGLM_GUI/adb/screenshot.py +11 -0
- {phone_agent/config → AutoGLM_GUI/adb}/timing.py +1 -1
- 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 +297 -0
- AutoGLM_GUI/agents/glm/message_builder.py +81 -0
- AutoGLM_GUI/agents/glm/parser.py +110 -0
- {phone_agent/config → AutoGLM_GUI/agents/glm}/prompts_en.py +7 -9
- {phone_agent/config → AutoGLM_GUI/agents/glm}/prompts_zh.py +18 -25
- AutoGLM_GUI/agents/mai/__init__.py +28 -0
- AutoGLM_GUI/agents/mai/agent.py +408 -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 +193 -0
- AutoGLM_GUI/api/__init__.py +40 -21
- AutoGLM_GUI/api/agents.py +181 -239
- AutoGLM_GUI/api/control.py +9 -6
- AutoGLM_GUI/api/devices.py +102 -12
- AutoGLM_GUI/api/history.py +104 -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/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 +140 -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 +350 -0
- AutoGLM_GUI/schemas.py +246 -72
- AutoGLM_GUI/scrcpy_stream.py +142 -24
- AutoGLM_GUI/socketio_server.py +100 -27
- AutoGLM_GUI/static/assets/{about-_XNhzQZX.js → about-CfwX1Cmc.js} +1 -1
- AutoGLM_GUI/static/assets/alert-dialog-CtGlN2IJ.js +1 -0
- AutoGLM_GUI/static/assets/chat-BYa-foUI.js +129 -0
- AutoGLM_GUI/static/assets/circle-alert-t08bEMPO.js +1 -0
- AutoGLM_GUI/static/assets/dialog-FNwZJFwk.js +45 -0
- AutoGLM_GUI/static/assets/eye-D0UPWCWC.js +1 -0
- AutoGLM_GUI/static/assets/history-CRo95B7i.js +1 -0
- AutoGLM_GUI/static/assets/{index-Cy8TmmHV.js → index-BaLMSqd3.js} +1 -1
- AutoGLM_GUI/static/assets/index-CTHbFvKl.js +11 -0
- AutoGLM_GUI/static/assets/index-CV7jGxGm.css +1 -0
- AutoGLM_GUI/static/assets/label-DJFevVmr.js +1 -0
- AutoGLM_GUI/static/assets/logs-RW09DyYY.js +1 -0
- AutoGLM_GUI/static/assets/popover--JTJrE5v.js +1 -0
- AutoGLM_GUI/static/assets/scheduled-tasks-DTRKsQXF.js +1 -0
- AutoGLM_GUI/static/assets/square-pen-CPK_K680.js +1 -0
- AutoGLM_GUI/static/assets/textarea-PRmVnWq5.js +1 -0
- AutoGLM_GUI/static/assets/workflows-CdcsAoaT.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.1.dist-info}/METADATA +179 -130
- autoglm_gui-1.5.1.dist-info/RECORD +118 -0
- AutoGLM_GUI/agents/mai_adapter.py +0 -627
- AutoGLM_GUI/api/dual_model.py +0 -317
- AutoGLM_GUI/device_adapter.py +0 -263
- 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
- mai_agent/base.py +0 -137
- mai_agent/mai_grounding_agent.py +0 -263
- mai_agent/mai_naivigation_agent.py +0 -526
- mai_agent/prompt.py +0 -148
- mai_agent/unified_memory.py +0 -67
- mai_agent/utils.py +0 -73
- phone_agent/__init__.py +0 -12
- phone_agent/actions/__init__.py +0 -5
- phone_agent/actions/handler.py +0 -400
- phone_agent/adb/screenshot.py +0 -108
- phone_agent/agent.py +0 -253
- phone_agent/agent_ios.py +0 -277
- phone_agent/config/__init__.py +0 -53
- phone_agent/config/apps_harmonyos.py +0 -256
- phone_agent/config/apps_ios.py +0 -339
- phone_agent/config/prompts.py +0 -80
- phone_agent/device_factory.py +0 -166
- phone_agent/hdc/__init__.py +0 -53
- phone_agent/hdc/connection.py +0 -384
- phone_agent/hdc/device.py +0 -269
- phone_agent/hdc/input.py +0 -145
- phone_agent/hdc/screenshot.py +0 -127
- phone_agent/model/__init__.py +0 -5
- phone_agent/model/client.py +0 -290
- phone_agent/xctest/__init__.py +0 -47
- phone_agent/xctest/connection.py +0 -379
- phone_agent/xctest/device.py +0 -472
- phone_agent/xctest/input.py +0 -311
- phone_agent/xctest/screenshot.py +0 -226
- {phone_agent/config → AutoGLM_GUI/adb}/apps.py +0 -0
- {phone_agent/config → AutoGLM_GUI}/i18n.py +0 -0
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/WHEEL +0 -0
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/entry_points.txt +0 -0
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/licenses/LICENSE +0 -0
AutoGLM_GUI/socketio_server.py
CHANGED
|
@@ -4,9 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import time
|
|
7
|
-
from typing import NotRequired
|
|
8
7
|
|
|
9
|
-
from typing_extensions import TypedDict
|
|
8
|
+
from typing_extensions import NotRequired, TypedDict
|
|
10
9
|
|
|
11
10
|
import socketio
|
|
12
11
|
|
|
@@ -31,6 +30,9 @@ sio = socketio.AsyncServer(
|
|
|
31
30
|
|
|
32
31
|
_socket_streamers: dict[str, ScrcpyStreamer] = {}
|
|
33
32
|
_stream_tasks: dict[str, asyncio.Task] = {}
|
|
33
|
+
_device_locks: dict[
|
|
34
|
+
str, asyncio.Lock
|
|
35
|
+
] = {} # Lock per device to prevent concurrent connections
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
async def _stop_stream_for_sid(sid: str) -> None:
|
|
@@ -43,6 +45,46 @@ async def _stop_stream_for_sid(sid: str) -> None:
|
|
|
43
45
|
streamer.stop()
|
|
44
46
|
|
|
45
47
|
|
|
48
|
+
def _classify_error(exc: Exception) -> dict:
|
|
49
|
+
"""Classify error and return user-friendly message."""
|
|
50
|
+
error_str = str(exc)
|
|
51
|
+
|
|
52
|
+
if "Address already in use" in error_str or (
|
|
53
|
+
"Port" in error_str and "occupied" in error_str
|
|
54
|
+
):
|
|
55
|
+
return {
|
|
56
|
+
"message": "端口冲突,视频流端口仍被占用。通常会自动解决,如果持续出现请重启应用。",
|
|
57
|
+
"type": "port_conflict",
|
|
58
|
+
"technical_details": error_str,
|
|
59
|
+
}
|
|
60
|
+
elif "Device" in error_str and (
|
|
61
|
+
"not available" in error_str or "not found" in error_str
|
|
62
|
+
):
|
|
63
|
+
return {
|
|
64
|
+
"message": "设备无响应,请检查 USB/WiFi 连接。",
|
|
65
|
+
"type": "device_offline",
|
|
66
|
+
"technical_details": error_str,
|
|
67
|
+
}
|
|
68
|
+
elif "timeout" in error_str.lower() or "timed out" in error_str.lower():
|
|
69
|
+
return {
|
|
70
|
+
"message": "连接超时,请检查设备连接后重试。",
|
|
71
|
+
"type": "timeout",
|
|
72
|
+
"technical_details": error_str,
|
|
73
|
+
}
|
|
74
|
+
elif "Failed to connect" in error_str:
|
|
75
|
+
return {
|
|
76
|
+
"message": "无法连接到 scrcpy 服务器,请检查设备连接。",
|
|
77
|
+
"type": "connection_failed",
|
|
78
|
+
"technical_details": error_str,
|
|
79
|
+
}
|
|
80
|
+
else:
|
|
81
|
+
return {
|
|
82
|
+
"message": error_str,
|
|
83
|
+
"type": "unknown",
|
|
84
|
+
"technical_details": error_str,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
46
88
|
def stop_streamers(device_id: str | None = None) -> None:
|
|
47
89
|
"""Stop active scrcpy streamers (all or by device)."""
|
|
48
90
|
sids = list(_socket_streamers.keys())
|
|
@@ -103,35 +145,66 @@ async def disconnect(sid: str) -> None:
|
|
|
103
145
|
async def connect_device(sid: str, data: dict | None) -> None:
|
|
104
146
|
payload = data or {}
|
|
105
147
|
device_id = payload.get("device_id") or payload.get("deviceId")
|
|
148
|
+
if not device_id:
|
|
149
|
+
await sio.emit(
|
|
150
|
+
"error",
|
|
151
|
+
{"message": "Device ID is required", "type": "invalid_request"},
|
|
152
|
+
to=sid,
|
|
153
|
+
)
|
|
154
|
+
return
|
|
155
|
+
|
|
106
156
|
max_size = int(payload.get("maxSize") or 1280)
|
|
107
157
|
bit_rate = int(payload.get("bitRate") or 4_000_000)
|
|
108
158
|
|
|
159
|
+
# Stop any existing stream for this sid
|
|
109
160
|
await _stop_stream_for_sid(sid)
|
|
110
161
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
162
|
+
# Get or create a lock for this device
|
|
163
|
+
if device_id not in _device_locks:
|
|
164
|
+
_device_locks[device_id] = asyncio.Lock()
|
|
165
|
+
|
|
166
|
+
device_lock = _device_locks[device_id]
|
|
167
|
+
|
|
168
|
+
# Acquire lock to prevent concurrent connections to the same device
|
|
169
|
+
async with device_lock:
|
|
170
|
+
logger.debug(f"Acquired device lock for {device_id}, sid: {sid}")
|
|
171
|
+
|
|
172
|
+
# Stop any existing streams for the same device (from other sids)
|
|
173
|
+
sids_to_stop = [
|
|
174
|
+
s
|
|
175
|
+
for s, streamer in _socket_streamers.items()
|
|
176
|
+
if s != sid and streamer.device_id == device_id
|
|
177
|
+
]
|
|
178
|
+
for s in sids_to_stop:
|
|
179
|
+
logger.info(f"Stopping existing stream for device {device_id} from sid {s}")
|
|
180
|
+
await _stop_stream_for_sid(s)
|
|
181
|
+
|
|
182
|
+
streamer = ScrcpyStreamer(
|
|
183
|
+
device_id=device_id,
|
|
184
|
+
max_size=max_size,
|
|
185
|
+
bit_rate=bit_rate,
|
|
129
186
|
)
|
|
130
|
-
except Exception as exc:
|
|
131
|
-
streamer.stop()
|
|
132
|
-
logger.exception("Failed to start scrcpy stream: %s", exc)
|
|
133
|
-
await sio.emit("error", {"message": str(exc)}, to=sid)
|
|
134
|
-
return
|
|
135
187
|
|
|
136
|
-
|
|
137
|
-
|
|
188
|
+
try:
|
|
189
|
+
await streamer.start() # ScrcpyStreamer has built-in retry logic
|
|
190
|
+
metadata = await streamer.read_video_metadata()
|
|
191
|
+
await sio.emit(
|
|
192
|
+
"video-metadata",
|
|
193
|
+
{
|
|
194
|
+
"deviceName": metadata.device_name,
|
|
195
|
+
"width": metadata.width,
|
|
196
|
+
"height": metadata.height,
|
|
197
|
+
"codec": metadata.codec,
|
|
198
|
+
},
|
|
199
|
+
to=sid,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
_socket_streamers[sid] = streamer
|
|
203
|
+
_stream_tasks[sid] = asyncio.create_task(_stream_packets(sid, streamer))
|
|
204
|
+
|
|
205
|
+
except Exception as exc:
|
|
206
|
+
streamer.stop()
|
|
207
|
+
logger.exception("Failed to start scrcpy stream: %s", exc)
|
|
208
|
+
# Use unified error classification
|
|
209
|
+
error_info = _classify_error(exc)
|
|
210
|
+
await sio.emit("error", error_info, to=sid)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as o}from"./index-
|
|
1
|
+
import{j as o}from"./index-CTHbFvKl.js";function t(){return o.jsx("div",{className:"p-2",children:o.jsx("h3",{children:"About"})})}export{t as component};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{o as u,r as o,j as a,b as r,B as d}from"./index-CTHbFvKl.js";import{P as g,c as x,b as f,d as m}from"./popover--JTJrE5v.js";import{D as p,d as h,e as w,f as j,g as D}from"./dialog-FNwZJFwk.js";const N=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],b=u("check",N),c=o.createContext(void 0),P=({value:t="",onValueChange:e,children:s})=>{const[n,l]=o.useState(!1);return a.jsx(c.Provider,{value:{value:t,onValueChange:e||(()=>{}),open:n,setOpen:l},children:a.jsx(g,{open:n,onOpenChange:l,children:s})})},C=o.forwardRef(({className:t,children:e,...s},n)=>{if(!o.useContext(c))throw new Error("SelectTrigger must be used within Select");return a.jsx(x,{asChild:!0,children:a.jsxs("button",{ref:n,className:r("flex h-10 w-full items-center justify-between rounded-md border border-slate-200 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-800 dark:bg-slate-950 dark:ring-offset-slate-950 dark:placeholder:text-slate-400 dark:focus:ring-slate-300",t),...s,children:[e,a.jsx(f,{className:"h-4 w-4 opacity-50"})]})})});C.displayName="SelectTrigger";const V=({placeholder:t})=>{const e=o.useContext(c);if(!e)throw new Error("SelectValue must be used within Select");return a.jsx("span",{className:e.value?"":"text-slate-500",children:e.value||t})},I=({children:t,className:e})=>a.jsx(m,{className:r("w-[var(--radix-popover-trigger-width)] p-1",e),children:t}),O=({value:t,children:e,disabled:s,className:n})=>{const l=o.useContext(c);if(!l)throw new Error("SelectItem must be used within Select");const i=l.value===t;return a.jsxs("div",{role:"option","aria-selected":i,className:r("relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none hover:bg-slate-100 focus:bg-slate-100 dark:hover:bg-slate-800 dark:focus:bg-slate-800",s&&"pointer-events-none opacity-50",n),onClick:()=>{s||(l.onValueChange(t),l.setOpen(!1))},children:[a.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:i&&a.jsx(b,{className:"h-4 w-4"})}),e]})},B=({open:t,onOpenChange:e,children:s})=>a.jsx(p,{open:t,onOpenChange:e,children:s}),v=o.forwardRef(({className:t,...e},s)=>a.jsx(h,{ref:s,className:r("sm:max-w-[425px]",t),...e}));v.displayName="AlertDialogContent";const F=({className:t,...e})=>a.jsx(w,{className:r(t),...e}),H=({className:t,...e})=>a.jsx(D,{className:r(t),...e}),A=o.forwardRef(({className:t,...e},s)=>a.jsx(j,{ref:s,className:r(t),...e}));A.displayName="AlertDialogTitle";const S=o.forwardRef(({className:t,...e},s)=>a.jsx("p",{ref:s,className:r("text-sm text-slate-500 dark:text-slate-400",t),...e}));S.displayName="AlertDialogDescription";const y=o.forwardRef(({className:t,...e},s)=>a.jsx(d,{ref:s,className:r(t),...e}));y.displayName="AlertDialogAction";const k=o.forwardRef(({className:t,...e},s)=>a.jsx(d,{ref:s,variant:"outline",className:r(t),...e}));k.displayName="AlertDialogCancel";export{B as A,P as S,C as a,V as b,I as c,O as d,v as e,F as f,A as g,S as h,H as i,k as j,y as k};
|