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
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Conversation history data models."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Literal
|
|
6
|
+
from uuid import uuid4
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class ConversationRecord:
|
|
11
|
+
"""单条对话记录."""
|
|
12
|
+
|
|
13
|
+
id: str = field(default_factory=lambda: str(uuid4()))
|
|
14
|
+
|
|
15
|
+
# 任务信息
|
|
16
|
+
task_text: str = "" # 用户输入的任务
|
|
17
|
+
final_message: str = "" # 最终结果消息
|
|
18
|
+
|
|
19
|
+
# 执行信息
|
|
20
|
+
success: bool = False
|
|
21
|
+
steps: int = 0
|
|
22
|
+
start_time: datetime = field(default_factory=datetime.now)
|
|
23
|
+
end_time: datetime | None = None
|
|
24
|
+
duration_ms: int = 0 # 执行时长(毫秒)
|
|
25
|
+
|
|
26
|
+
# 来源标记
|
|
27
|
+
source: Literal["chat", "layered", "scheduled"] = "chat"
|
|
28
|
+
source_detail: str = "" # 定时任务名称 or session_id
|
|
29
|
+
|
|
30
|
+
# 错误信息
|
|
31
|
+
error_message: str | None = None
|
|
32
|
+
|
|
33
|
+
def to_dict(self) -> dict:
|
|
34
|
+
"""转换为可序列化的字典."""
|
|
35
|
+
return {
|
|
36
|
+
"id": self.id,
|
|
37
|
+
"task_text": self.task_text,
|
|
38
|
+
"final_message": self.final_message,
|
|
39
|
+
"success": self.success,
|
|
40
|
+
"steps": self.steps,
|
|
41
|
+
"start_time": self.start_time.isoformat(),
|
|
42
|
+
"end_time": self.end_time.isoformat() if self.end_time else None,
|
|
43
|
+
"duration_ms": self.duration_ms,
|
|
44
|
+
"source": self.source,
|
|
45
|
+
"source_detail": self.source_detail,
|
|
46
|
+
"error_message": self.error_message,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def from_dict(cls, data: dict) -> "ConversationRecord":
|
|
51
|
+
"""从字典创建实例."""
|
|
52
|
+
return cls(
|
|
53
|
+
id=data.get("id", str(uuid4())),
|
|
54
|
+
task_text=data.get("task_text", ""),
|
|
55
|
+
final_message=data.get("final_message", ""),
|
|
56
|
+
success=data.get("success", False),
|
|
57
|
+
steps=data.get("steps", 0),
|
|
58
|
+
start_time=datetime.fromisoformat(data["start_time"])
|
|
59
|
+
if data.get("start_time")
|
|
60
|
+
else datetime.now(),
|
|
61
|
+
end_time=datetime.fromisoformat(data["end_time"])
|
|
62
|
+
if data.get("end_time")
|
|
63
|
+
else None,
|
|
64
|
+
duration_ms=data.get("duration_ms", 0),
|
|
65
|
+
source=data.get("source", "chat"),
|
|
66
|
+
source_detail=data.get("source_detail", ""),
|
|
67
|
+
error_message=data.get("error_message"),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class DeviceHistory:
|
|
73
|
+
"""设备对话历史(一个设备一个文件)."""
|
|
74
|
+
|
|
75
|
+
serialno: str
|
|
76
|
+
records: list[ConversationRecord] = field(default_factory=list)
|
|
77
|
+
last_updated: datetime = field(default_factory=datetime.now)
|
|
78
|
+
|
|
79
|
+
def to_dict(self) -> dict:
|
|
80
|
+
"""转换为可序列化的字典."""
|
|
81
|
+
return {
|
|
82
|
+
"serialno": self.serialno,
|
|
83
|
+
"records": [r.to_dict() for r in self.records],
|
|
84
|
+
"last_updated": self.last_updated.isoformat(),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def from_dict(cls, data: dict) -> "DeviceHistory":
|
|
89
|
+
"""从字典创建实例."""
|
|
90
|
+
return cls(
|
|
91
|
+
serialno=data.get("serialno", ""),
|
|
92
|
+
records=[ConversationRecord.from_dict(r) for r in data.get("records", [])],
|
|
93
|
+
last_updated=datetime.fromisoformat(data["last_updated"])
|
|
94
|
+
if data.get("last_updated")
|
|
95
|
+
else datetime.now(),
|
|
96
|
+
)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Scheduled task data models."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class ScheduledTask:
|
|
10
|
+
"""定时任务定义."""
|
|
11
|
+
|
|
12
|
+
id: str = field(default_factory=lambda: str(uuid4()))
|
|
13
|
+
|
|
14
|
+
# 基础信息
|
|
15
|
+
name: str = "" # 任务名称
|
|
16
|
+
workflow_uuid: str = "" # 关联的 Workflow UUID
|
|
17
|
+
device_serialno: str = "" # 绑定的设备 serialno
|
|
18
|
+
|
|
19
|
+
# 调度配置
|
|
20
|
+
cron_expression: str = "" # Cron 表达式 (如 "0 8 * * *")
|
|
21
|
+
enabled: bool = True # 是否启用
|
|
22
|
+
|
|
23
|
+
# 元数据
|
|
24
|
+
created_at: datetime = field(default_factory=datetime.now)
|
|
25
|
+
updated_at: datetime = field(default_factory=datetime.now)
|
|
26
|
+
|
|
27
|
+
# 最近执行信息(只记录最后一次)
|
|
28
|
+
last_run_time: datetime | None = None
|
|
29
|
+
last_run_success: bool | None = None
|
|
30
|
+
last_run_message: str | None = None
|
|
31
|
+
|
|
32
|
+
def to_dict(self) -> dict:
|
|
33
|
+
"""转换为可序列化的字典."""
|
|
34
|
+
return {
|
|
35
|
+
"id": self.id,
|
|
36
|
+
"name": self.name,
|
|
37
|
+
"workflow_uuid": self.workflow_uuid,
|
|
38
|
+
"device_serialno": self.device_serialno,
|
|
39
|
+
"cron_expression": self.cron_expression,
|
|
40
|
+
"enabled": self.enabled,
|
|
41
|
+
"created_at": self.created_at.isoformat(),
|
|
42
|
+
"updated_at": self.updated_at.isoformat(),
|
|
43
|
+
"last_run_time": self.last_run_time.isoformat()
|
|
44
|
+
if self.last_run_time
|
|
45
|
+
else None,
|
|
46
|
+
"last_run_success": self.last_run_success,
|
|
47
|
+
"last_run_message": self.last_run_message,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def from_dict(cls, data: dict) -> "ScheduledTask":
|
|
52
|
+
"""从字典创建实例."""
|
|
53
|
+
return cls(
|
|
54
|
+
id=data.get("id", str(uuid4())),
|
|
55
|
+
name=data.get("name", ""),
|
|
56
|
+
workflow_uuid=data.get("workflow_uuid", ""),
|
|
57
|
+
device_serialno=data.get("device_serialno", ""),
|
|
58
|
+
cron_expression=data.get("cron_expression", ""),
|
|
59
|
+
enabled=data.get("enabled", True),
|
|
60
|
+
created_at=datetime.fromisoformat(data["created_at"])
|
|
61
|
+
if data.get("created_at")
|
|
62
|
+
else datetime.now(),
|
|
63
|
+
updated_at=datetime.fromisoformat(data["updated_at"])
|
|
64
|
+
if data.get("updated_at")
|
|
65
|
+
else datetime.now(),
|
|
66
|
+
last_run_time=datetime.fromisoformat(data["last_run_time"])
|
|
67
|
+
if data.get("last_run_time")
|
|
68
|
+
else None,
|
|
69
|
+
last_run_success=data.get("last_run_success"),
|
|
70
|
+
last_run_message=data.get("last_run_message"),
|
|
71
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Action parsers for different agent types.
|
|
2
|
+
|
|
3
|
+
This module provides parser implementations for converting model outputs
|
|
4
|
+
into standardized action dictionaries that can be executed by ActionHandler.
|
|
5
|
+
|
|
6
|
+
Each agent type has its own parser implementation:
|
|
7
|
+
- GLMParser: For GLM-based agents (enhanced AST parsing)
|
|
8
|
+
- PhoneAgentParser: For standard PhoneAgent (basic AST parsing)
|
|
9
|
+
- MAIParser: For MAI agent (XML + JSON parsing)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from .base import ActionParser
|
|
13
|
+
from AutoGLM_GUI.agents.glm.parser import GLMParser
|
|
14
|
+
from AutoGLM_GUI.agents.mai.parser import MAIParser
|
|
15
|
+
from .phone_parser import PhoneAgentParser
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"ActionParser",
|
|
19
|
+
"GLMParser",
|
|
20
|
+
"MAIParser",
|
|
21
|
+
"PhoneAgentParser",
|
|
22
|
+
]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Base protocol for action parsers.
|
|
2
|
+
|
|
3
|
+
This module defines the interface that all action parsers must implement.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any, Protocol
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ActionParser(Protocol):
|
|
10
|
+
"""Protocol for parsing model outputs into action dictionaries.
|
|
11
|
+
|
|
12
|
+
All parser implementations must provide:
|
|
13
|
+
1. parse() method to convert raw model output into standardized action dict
|
|
14
|
+
2. coordinate_scale property to specify the coordinate normalization range
|
|
15
|
+
|
|
16
|
+
The standardized action dictionary format:
|
|
17
|
+
{
|
|
18
|
+
"_metadata": "do" | "finish",
|
|
19
|
+
"action": "Tap" | "Swipe" | "Type" | ..., # Only when _metadata="do"
|
|
20
|
+
"coordinate": [x, y], # Normalized to 0-1000 range
|
|
21
|
+
"text": "...", # For Type action
|
|
22
|
+
... # Other action-specific parameters
|
|
23
|
+
}
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def parse(self, raw_response: str) -> dict[str, Any]:
|
|
27
|
+
"""Parse raw model output into standardized action dictionary.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
raw_response: Raw text output from the model.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Standardized action dictionary with:
|
|
34
|
+
- "_metadata": "do" or "finish"
|
|
35
|
+
- "action": Action type (Tap, Swipe, etc.) when _metadata="do"
|
|
36
|
+
- Additional parameters based on action type
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
ValueError: If the response cannot be parsed.
|
|
40
|
+
"""
|
|
41
|
+
...
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def coordinate_scale(self) -> int:
|
|
45
|
+
"""Get the coordinate normalization scale used by this parser.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
999 for MAI parser, 1000 for GLM/PhoneAgent parsers.
|
|
49
|
+
"""
|
|
50
|
+
...
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""PhoneAgent parser using standard AST parsing."""
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PhoneAgentParser:
|
|
8
|
+
"""Parse PhoneAgent function-call style outputs using ast.parse.
|
|
9
|
+
|
|
10
|
+
Handles the same format as GLM but with simpler AST-based parsing.
|
|
11
|
+
Includes special handling for Type action to avoid parsing issues.
|
|
12
|
+
Coordinate scale: 0-1000
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def coordinate_scale(self) -> int:
|
|
17
|
+
return 1000
|
|
18
|
+
|
|
19
|
+
def parse(self, raw_response: str) -> dict[str, Any]:
|
|
20
|
+
response = raw_response.strip()
|
|
21
|
+
|
|
22
|
+
if response.startswith('do(action="Type"') or response.startswith(
|
|
23
|
+
'do(action="Type_Name"'
|
|
24
|
+
):
|
|
25
|
+
text = response.split("text=", 1)[1][1:-2]
|
|
26
|
+
action = {"_metadata": "do", "action": "Type", "text": text}
|
|
27
|
+
return action
|
|
28
|
+
elif response.startswith("do"):
|
|
29
|
+
try:
|
|
30
|
+
response = response.replace("\n", "\\n")
|
|
31
|
+
response = response.replace("\r", "\\r")
|
|
32
|
+
response = response.replace("\t", "\\t")
|
|
33
|
+
|
|
34
|
+
tree = ast.parse(response, mode="eval")
|
|
35
|
+
if not isinstance(tree.body, ast.Call):
|
|
36
|
+
raise ValueError("Expected a function call")
|
|
37
|
+
|
|
38
|
+
call = tree.body
|
|
39
|
+
action = {"_metadata": "do"}
|
|
40
|
+
for keyword in call.keywords:
|
|
41
|
+
key = keyword.arg
|
|
42
|
+
if key is None:
|
|
43
|
+
raise ValueError("Keyword argument name missing")
|
|
44
|
+
value = ast.literal_eval(keyword.value)
|
|
45
|
+
action[key] = value
|
|
46
|
+
|
|
47
|
+
return action
|
|
48
|
+
except (SyntaxError, ValueError) as e:
|
|
49
|
+
raise ValueError(f"Failed to parse do() action: {e}") from e
|
|
50
|
+
|
|
51
|
+
elif response.startswith("finish"):
|
|
52
|
+
action = {
|
|
53
|
+
"_metadata": "finish",
|
|
54
|
+
"message": response.replace("finish(message=", "")[1:-2],
|
|
55
|
+
}
|
|
56
|
+
return action
|
|
57
|
+
else:
|
|
58
|
+
raise ValueError(f"Failed to parse action: {response}")
|