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/media.py
CHANGED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from fastapi import APIRouter
|
|
6
6
|
|
|
7
7
|
from AutoGLM_GUI.adb_plus import capture_screenshot
|
|
8
|
+
from AutoGLM_GUI.exceptions import DeviceNotAvailableError
|
|
8
9
|
from AutoGLM_GUI.logger import logger
|
|
9
10
|
from AutoGLM_GUI.schemas import ScreenshotRequest, ScreenshotResponse
|
|
10
11
|
from AutoGLM_GUI.socketio_server import stop_streamers
|
|
@@ -29,8 +30,59 @@ async def reset_video_stream(device_id: str | None = None) -> dict:
|
|
|
29
30
|
@router.post("/api/screenshot", response_model=ScreenshotResponse)
|
|
30
31
|
def take_screenshot(request: ScreenshotRequest) -> ScreenshotResponse:
|
|
31
32
|
"""获取设备截图。此操作无副作用,不影响 PhoneAgent 运行。"""
|
|
33
|
+
from AutoGLM_GUI.device_manager import DeviceManager
|
|
34
|
+
|
|
32
35
|
try:
|
|
33
|
-
|
|
36
|
+
device_id = request.device_id
|
|
37
|
+
|
|
38
|
+
if not device_id:
|
|
39
|
+
return ScreenshotResponse(
|
|
40
|
+
success=False,
|
|
41
|
+
image="",
|
|
42
|
+
width=0,
|
|
43
|
+
height=0,
|
|
44
|
+
is_sensitive=False,
|
|
45
|
+
error="device_id is required",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
device_manager = DeviceManager.get_instance()
|
|
49
|
+
serial = device_manager.get_serial_by_device_id(device_id)
|
|
50
|
+
|
|
51
|
+
if not serial:
|
|
52
|
+
return ScreenshotResponse(
|
|
53
|
+
success=False,
|
|
54
|
+
image="",
|
|
55
|
+
width=0,
|
|
56
|
+
height=0,
|
|
57
|
+
is_sensitive=False,
|
|
58
|
+
error=f"Device {device_id} not found",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if serial:
|
|
62
|
+
managed = device_manager._devices.get(serial)
|
|
63
|
+
if managed and managed.connection_type.value == "remote":
|
|
64
|
+
remote_device = device_manager.get_remote_device_instance(serial)
|
|
65
|
+
|
|
66
|
+
if not remote_device:
|
|
67
|
+
return ScreenshotResponse(
|
|
68
|
+
success=False,
|
|
69
|
+
image="",
|
|
70
|
+
width=0,
|
|
71
|
+
height=0,
|
|
72
|
+
is_sensitive=False,
|
|
73
|
+
error=f"Remote device {serial} not found",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
screenshot = remote_device.get_screenshot(timeout=10) # type: ignore
|
|
77
|
+
return ScreenshotResponse(
|
|
78
|
+
success=True,
|
|
79
|
+
image=screenshot.base64_data,
|
|
80
|
+
width=screenshot.width,
|
|
81
|
+
height=screenshot.height,
|
|
82
|
+
is_sensitive=screenshot.is_sensitive,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
screenshot = capture_screenshot(device_id=device_id)
|
|
34
86
|
return ScreenshotResponse(
|
|
35
87
|
success=True,
|
|
36
88
|
image=screenshot.base64_data,
|
|
@@ -38,7 +90,18 @@ def take_screenshot(request: ScreenshotRequest) -> ScreenshotResponse:
|
|
|
38
90
|
height=screenshot.height,
|
|
39
91
|
is_sensitive=screenshot.is_sensitive,
|
|
40
92
|
)
|
|
93
|
+
except DeviceNotAvailableError as e:
|
|
94
|
+
logger.warning("Screenshot failed - device not available: %s", e)
|
|
95
|
+
return ScreenshotResponse(
|
|
96
|
+
success=False,
|
|
97
|
+
image="",
|
|
98
|
+
width=0,
|
|
99
|
+
height=0,
|
|
100
|
+
is_sensitive=False,
|
|
101
|
+
error=str(e),
|
|
102
|
+
)
|
|
41
103
|
except Exception as e:
|
|
104
|
+
logger.exception("Screenshot failed for device %s", request.device_id)
|
|
42
105
|
return ScreenshotResponse(
|
|
43
106
|
success=False,
|
|
44
107
|
image="",
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Scheduled tasks API routes."""
|
|
2
|
+
|
|
3
|
+
from fastapi import APIRouter, HTTPException
|
|
4
|
+
|
|
5
|
+
from AutoGLM_GUI.scheduler_manager import scheduler_manager
|
|
6
|
+
from AutoGLM_GUI.schemas import (
|
|
7
|
+
ScheduledTaskCreate,
|
|
8
|
+
ScheduledTaskListResponse,
|
|
9
|
+
ScheduledTaskResponse,
|
|
10
|
+
ScheduledTaskUpdate,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
router = APIRouter()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _task_to_response(task) -> ScheduledTaskResponse:
|
|
17
|
+
next_run = scheduler_manager.get_next_run_time(task.id)
|
|
18
|
+
return ScheduledTaskResponse(
|
|
19
|
+
id=task.id,
|
|
20
|
+
name=task.name,
|
|
21
|
+
workflow_uuid=task.workflow_uuid,
|
|
22
|
+
device_serialno=task.device_serialno,
|
|
23
|
+
cron_expression=task.cron_expression,
|
|
24
|
+
enabled=task.enabled,
|
|
25
|
+
created_at=task.created_at.isoformat(),
|
|
26
|
+
updated_at=task.updated_at.isoformat(),
|
|
27
|
+
last_run_time=task.last_run_time.isoformat() if task.last_run_time else None,
|
|
28
|
+
last_run_success=task.last_run_success,
|
|
29
|
+
last_run_message=task.last_run_message,
|
|
30
|
+
next_run_time=next_run.isoformat() if next_run else None,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@router.get("/api/scheduled-tasks", response_model=ScheduledTaskListResponse)
|
|
35
|
+
def list_scheduled_tasks() -> ScheduledTaskListResponse:
|
|
36
|
+
tasks = scheduler_manager.list_tasks()
|
|
37
|
+
return ScheduledTaskListResponse(tasks=[_task_to_response(t) for t in tasks])
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@router.post("/api/scheduled-tasks", response_model=ScheduledTaskResponse)
|
|
41
|
+
def create_scheduled_task(request: ScheduledTaskCreate) -> ScheduledTaskResponse:
|
|
42
|
+
from AutoGLM_GUI.workflow_manager import workflow_manager
|
|
43
|
+
|
|
44
|
+
workflow = workflow_manager.get_workflow(request.workflow_uuid)
|
|
45
|
+
if not workflow:
|
|
46
|
+
raise HTTPException(status_code=400, detail="Workflow not found")
|
|
47
|
+
|
|
48
|
+
task = scheduler_manager.create_task(
|
|
49
|
+
name=request.name,
|
|
50
|
+
workflow_uuid=request.workflow_uuid,
|
|
51
|
+
device_serialno=request.device_serialno,
|
|
52
|
+
cron_expression=request.cron_expression,
|
|
53
|
+
enabled=request.enabled,
|
|
54
|
+
)
|
|
55
|
+
return _task_to_response(task)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@router.get("/api/scheduled-tasks/{task_id}", response_model=ScheduledTaskResponse)
|
|
59
|
+
def get_scheduled_task(task_id: str) -> ScheduledTaskResponse:
|
|
60
|
+
task = scheduler_manager.get_task(task_id)
|
|
61
|
+
if not task:
|
|
62
|
+
raise HTTPException(status_code=404, detail="Task not found")
|
|
63
|
+
return _task_to_response(task)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@router.put("/api/scheduled-tasks/{task_id}", response_model=ScheduledTaskResponse)
|
|
67
|
+
def update_scheduled_task(
|
|
68
|
+
task_id: str, request: ScheduledTaskUpdate
|
|
69
|
+
) -> ScheduledTaskResponse:
|
|
70
|
+
update_data = request.model_dump(exclude_unset=True)
|
|
71
|
+
task = scheduler_manager.update_task(task_id, **update_data)
|
|
72
|
+
if not task:
|
|
73
|
+
raise HTTPException(status_code=404, detail="Task not found")
|
|
74
|
+
return _task_to_response(task)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@router.delete("/api/scheduled-tasks/{task_id}")
|
|
78
|
+
def delete_scheduled_task(task_id: str) -> dict:
|
|
79
|
+
success = scheduler_manager.delete_task(task_id)
|
|
80
|
+
if not success:
|
|
81
|
+
raise HTTPException(status_code=404, detail="Task not found")
|
|
82
|
+
return {"success": True, "message": "Task deleted"}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@router.post("/api/scheduled-tasks/{task_id}/enable")
|
|
86
|
+
def enable_scheduled_task(task_id: str) -> dict:
|
|
87
|
+
success = scheduler_manager.set_enabled(task_id, True)
|
|
88
|
+
if not success:
|
|
89
|
+
raise HTTPException(status_code=404, detail="Task not found")
|
|
90
|
+
return {"success": True, "message": "Task enabled"}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@router.post("/api/scheduled-tasks/{task_id}/disable")
|
|
94
|
+
def disable_scheduled_task(task_id: str) -> dict:
|
|
95
|
+
success = scheduler_manager.set_enabled(task_id, False)
|
|
96
|
+
if not success:
|
|
97
|
+
raise HTTPException(status_code=404, detail="Task not found")
|
|
98
|
+
return {"success": True, "message": "Task disabled"}
|
AutoGLM_GUI/api/version.py
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
import json
|
|
4
4
|
import re
|
|
5
5
|
import time
|
|
6
|
+
import urllib.error
|
|
6
7
|
import urllib.request
|
|
7
|
-
from
|
|
8
|
+
from typing_extensions import TypedDict
|
|
8
9
|
|
|
9
10
|
from fastapi import APIRouter
|
|
10
11
|
|
|
@@ -12,13 +13,30 @@ from AutoGLM_GUI.logger import logger
|
|
|
12
13
|
from AutoGLM_GUI.schemas import VersionCheckResponse
|
|
13
14
|
from AutoGLM_GUI.version import APP_VERSION
|
|
14
15
|
|
|
16
|
+
|
|
17
|
+
class GitHubRelease(TypedDict, total=False):
|
|
18
|
+
"""GitHub Release API response structure."""
|
|
19
|
+
|
|
20
|
+
tag_name: str
|
|
21
|
+
html_url: str
|
|
22
|
+
published_at: str
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class _VersionCache(TypedDict):
|
|
26
|
+
"""Internal cache structure for version checking."""
|
|
27
|
+
|
|
28
|
+
data: VersionCheckResponse | None
|
|
29
|
+
timestamp: float
|
|
30
|
+
ttl: int
|
|
31
|
+
|
|
32
|
+
|
|
15
33
|
router = APIRouter()
|
|
16
34
|
|
|
17
35
|
# In-memory cache for version check results
|
|
18
|
-
_version_cache:
|
|
36
|
+
_version_cache: _VersionCache = {
|
|
19
37
|
"data": None,
|
|
20
38
|
"timestamp": 0,
|
|
21
|
-
"ttl": 3600,
|
|
39
|
+
"ttl": 3600,
|
|
22
40
|
}
|
|
23
41
|
|
|
24
42
|
# GitHub repository information
|
|
@@ -74,13 +92,8 @@ def compare_versions(current: str, latest: str) -> bool:
|
|
|
74
92
|
return latest_tuple > current_tuple
|
|
75
93
|
|
|
76
94
|
|
|
77
|
-
def fetch_latest_release() ->
|
|
78
|
-
"""
|
|
79
|
-
Fetch latest release information from GitHub API.
|
|
80
|
-
|
|
81
|
-
Returns:
|
|
82
|
-
Release data dict with 'tag_name', 'html_url', 'published_at' or None on error
|
|
83
|
-
"""
|
|
95
|
+
def fetch_latest_release() -> GitHubRelease | None:
|
|
96
|
+
"""Fetch latest release information from GitHub API."""
|
|
84
97
|
try:
|
|
85
98
|
# Create request with User-Agent header (required by GitHub API)
|
|
86
99
|
req = urllib.request.Request(
|
AutoGLM_GUI/api/workflows.py
CHANGED
|
@@ -17,7 +17,8 @@ def list_workflows() -> WorkflowListResponse:
|
|
|
17
17
|
"""获取所有 workflows."""
|
|
18
18
|
from AutoGLM_GUI.workflow_manager import workflow_manager
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
workflow_dicts = workflow_manager.list_workflows()
|
|
21
|
+
workflows = [WorkflowResponse(**wf) for wf in workflow_dicts]
|
|
21
22
|
return WorkflowListResponse(workflows=workflows)
|
|
22
23
|
|
|
23
24
|
|
AutoGLM_GUI/config.py
CHANGED
|
@@ -1,23 +1,81 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""AutoGLM-GUI 核心配置定义
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
这个模块定义了项目自己的配置类,替代 phone_agent 的配置,
|
|
4
|
+
实现配置层的解耦和扩展性。
|
|
5
|
+
|
|
6
|
+
设计原则:
|
|
7
|
+
- 配置类提供 AutoGLM-GUI 核心业务逻辑所需的参数
|
|
8
|
+
- 避免在 API 层和业务层直接使用外部库的类型
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from typing import Any
|
|
5
13
|
|
|
6
14
|
|
|
7
15
|
@dataclass
|
|
8
|
-
class
|
|
9
|
-
"""
|
|
16
|
+
class ModelConfig:
|
|
17
|
+
"""模型配置
|
|
10
18
|
|
|
11
|
-
|
|
12
|
-
|
|
19
|
+
OpenAI 兼容 API 的配置参数。
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
base_url: API 端点 URL (例如: "http://localhost:8000/v1")
|
|
23
|
+
api_key: API 认证密钥 (本地部署可选)
|
|
24
|
+
model_name: 模型标识符 (例如: "autoglm-phone-9b")
|
|
25
|
+
max_tokens: 响应最大 token 数 (默认: 3000)
|
|
26
|
+
temperature: 采样温度 0-1 (默认: 0.0)
|
|
27
|
+
top_p: Nucleus 采样阈值 (默认: 0.85)
|
|
28
|
+
frequency_penalty: 频率惩罚 -2 到 2 (默认: 0.2)
|
|
29
|
+
extra_body: 特定后端的额外参数
|
|
30
|
+
lang: UI 消息语言: 'cn' 或 'en'
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
base_url: str = "http://localhost:8000/v1"
|
|
13
34
|
api_key: str = "EMPTY"
|
|
35
|
+
model_name: str = "autoglm-phone-9b"
|
|
36
|
+
max_tokens: int = 3000
|
|
37
|
+
temperature: float = 0.0
|
|
38
|
+
top_p: float = 0.85
|
|
39
|
+
frequency_penalty: float = 0.2
|
|
40
|
+
extra_body: dict[str, Any] = field(default_factory=dict)
|
|
41
|
+
lang: str = "cn"
|
|
42
|
+
|
|
14
43
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
44
|
+
@dataclass
|
|
45
|
+
class AgentConfig:
|
|
46
|
+
"""Agent 配置
|
|
47
|
+
|
|
48
|
+
控制 Agent 的行为参数。
|
|
49
|
+
|
|
50
|
+
Attributes:
|
|
51
|
+
max_steps: 单次任务最大执行步数 (默认: 100)
|
|
52
|
+
device_id: 设备标识符 (USB serial 或 IP:port)
|
|
53
|
+
lang: 语言设置 'cn' 或 'en'
|
|
54
|
+
system_prompt: 自定义系统提示词 (None 则使用默认)
|
|
55
|
+
verbose: 是否输出详细日志
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
max_steps: int = 100
|
|
59
|
+
device_id: str | None = None
|
|
60
|
+
lang: str = "cn"
|
|
61
|
+
system_prompt: str | None = None
|
|
62
|
+
verbose: bool = True
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class StepResult:
|
|
67
|
+
"""Agent 单步执行结果
|
|
20
68
|
|
|
69
|
+
Attributes:
|
|
70
|
+
success: 本步骤是否执行成功
|
|
71
|
+
finished: 整个任务是否已完成
|
|
72
|
+
action: 执行的动作字典 (包含 action type 和参数)
|
|
73
|
+
thinking: Agent 的思考过程
|
|
74
|
+
message: 结果消息 (可选)
|
|
75
|
+
"""
|
|
21
76
|
|
|
22
|
-
|
|
23
|
-
|
|
77
|
+
success: bool
|
|
78
|
+
finished: bool
|
|
79
|
+
action: dict[str, Any] | None
|
|
80
|
+
thinking: str
|
|
81
|
+
message: str | None = None
|
AutoGLM_GUI/config_manager.py
CHANGED
|
@@ -52,11 +52,27 @@ class ConfigModel(BaseModel):
|
|
|
52
52
|
model_name: str = "autoglm-phone-9b"
|
|
53
53
|
api_key: str = "EMPTY"
|
|
54
54
|
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
# Agent 类型配置
|
|
56
|
+
agent_type: str = "glm" # Agent type (e.g., "glm", "mai")
|
|
57
|
+
agent_config_params: dict | None = None # Agent-specific configuration
|
|
58
|
+
|
|
59
|
+
# Agent 执行配置
|
|
60
|
+
default_max_steps: int = 100 # 单次任务最大执行步数
|
|
61
|
+
|
|
62
|
+
# 决策模型配置(用于分层代理)
|
|
63
|
+
decision_base_url: str | None = None
|
|
64
|
+
decision_model_name: str | None = None
|
|
65
|
+
decision_api_key: str | None = None
|
|
66
|
+
|
|
67
|
+
@field_validator("default_max_steps")
|
|
68
|
+
@classmethod
|
|
69
|
+
def validate_default_max_steps(cls, v: int) -> int:
|
|
70
|
+
"""验证 default_max_steps 范围."""
|
|
71
|
+
if v <= 0:
|
|
72
|
+
raise ValueError("default_max_steps must be positive")
|
|
73
|
+
if v > 1000:
|
|
74
|
+
raise ValueError("default_max_steps must be <= 1000")
|
|
75
|
+
return v
|
|
60
76
|
|
|
61
77
|
@field_validator("base_url")
|
|
62
78
|
@classmethod
|
|
@@ -76,11 +92,23 @@ class ConfigModel(BaseModel):
|
|
|
76
92
|
|
|
77
93
|
@field_validator("decision_base_url")
|
|
78
94
|
@classmethod
|
|
79
|
-
def validate_decision_base_url(cls, v: str) -> str:
|
|
95
|
+
def validate_decision_base_url(cls, v: str | None) -> str | None:
|
|
80
96
|
"""验证 decision_base_url 格式."""
|
|
81
|
-
if v
|
|
82
|
-
|
|
83
|
-
|
|
97
|
+
if v is not None:
|
|
98
|
+
if not v.startswith(("http://", "https://")):
|
|
99
|
+
raise ValueError(
|
|
100
|
+
"decision_base_url must start with http:// or https://"
|
|
101
|
+
)
|
|
102
|
+
return v.rstrip("/")
|
|
103
|
+
return v
|
|
104
|
+
|
|
105
|
+
@field_validator("decision_model_name")
|
|
106
|
+
@classmethod
|
|
107
|
+
def validate_decision_model_name(cls, v: str | None) -> str | None:
|
|
108
|
+
"""验证 decision_model_name 非空."""
|
|
109
|
+
if v is not None and (not v or not v.strip()):
|
|
110
|
+
raise ValueError("decision_model_name cannot be empty string")
|
|
111
|
+
return v.strip() if v else v
|
|
84
112
|
|
|
85
113
|
|
|
86
114
|
# ==================== 配置层数据类 ====================
|
|
@@ -93,8 +121,12 @@ class ConfigLayer:
|
|
|
93
121
|
base_url: Optional[str] = None
|
|
94
122
|
model_name: Optional[str] = None
|
|
95
123
|
api_key: Optional[str] = None
|
|
96
|
-
#
|
|
97
|
-
|
|
124
|
+
# Agent 类型配置
|
|
125
|
+
agent_type: Optional[str] = None
|
|
126
|
+
agent_config_params: Optional[dict] = None
|
|
127
|
+
# Agent 执行配置
|
|
128
|
+
default_max_steps: Optional[int] = None
|
|
129
|
+
# 决策模型配置
|
|
98
130
|
decision_base_url: Optional[str] = None
|
|
99
131
|
decision_model_name: Optional[str] = None
|
|
100
132
|
decision_api_key: Optional[str] = None
|
|
@@ -125,7 +157,9 @@ class ConfigLayer:
|
|
|
125
157
|
"base_url": self.base_url,
|
|
126
158
|
"model_name": self.model_name,
|
|
127
159
|
"api_key": self.api_key,
|
|
128
|
-
"
|
|
160
|
+
"agent_type": self.agent_type,
|
|
161
|
+
"agent_config_params": self.agent_config_params,
|
|
162
|
+
"default_max_steps": self.default_max_steps,
|
|
129
163
|
"decision_base_url": self.decision_base_url,
|
|
130
164
|
"decision_model_name": self.decision_model_name,
|
|
131
165
|
"decision_api_key": self.decision_api_key,
|
|
@@ -188,6 +222,12 @@ class UnifiedConfigManager:
|
|
|
188
222
|
base_url="",
|
|
189
223
|
model_name="autoglm-phone-9b",
|
|
190
224
|
api_key="EMPTY",
|
|
225
|
+
agent_type="glm",
|
|
226
|
+
agent_config_params=None,
|
|
227
|
+
default_max_steps=100,
|
|
228
|
+
decision_base_url=None,
|
|
229
|
+
decision_model_name=None,
|
|
230
|
+
decision_api_key=None,
|
|
191
231
|
source=ConfigSource.DEFAULT,
|
|
192
232
|
)
|
|
193
233
|
|
|
@@ -234,15 +274,26 @@ class UnifiedConfigManager:
|
|
|
234
274
|
- AUTOGLM_BASE_URL
|
|
235
275
|
- AUTOGLM_MODEL_NAME
|
|
236
276
|
- AUTOGLM_API_KEY
|
|
277
|
+
- AUTOGLM_DECISION_BASE_URL
|
|
278
|
+
- AUTOGLM_DECISION_MODEL_NAME
|
|
279
|
+
- AUTOGLM_DECISION_API_KEY
|
|
237
280
|
"""
|
|
238
281
|
base_url = os.getenv("AUTOGLM_BASE_URL")
|
|
239
282
|
model_name = os.getenv("AUTOGLM_MODEL_NAME")
|
|
240
283
|
api_key = os.getenv("AUTOGLM_API_KEY")
|
|
241
284
|
|
|
285
|
+
# 决策模型环境变量
|
|
286
|
+
decision_base_url = os.getenv("AUTOGLM_DECISION_BASE_URL")
|
|
287
|
+
decision_model_name = os.getenv("AUTOGLM_DECISION_MODEL_NAME")
|
|
288
|
+
decision_api_key = os.getenv("AUTOGLM_DECISION_API_KEY")
|
|
289
|
+
|
|
242
290
|
self._env_layer = ConfigLayer(
|
|
243
291
|
base_url=base_url if base_url else None,
|
|
244
292
|
model_name=model_name if model_name else None,
|
|
245
293
|
api_key=api_key if api_key else None,
|
|
294
|
+
decision_base_url=decision_base_url if decision_base_url else None,
|
|
295
|
+
decision_model_name=decision_model_name if decision_model_name else None,
|
|
296
|
+
decision_api_key=decision_api_key if decision_api_key else None,
|
|
246
297
|
source=ConfigSource.ENV,
|
|
247
298
|
)
|
|
248
299
|
self._effective_config = None # 清除缓存
|
|
@@ -296,7 +347,11 @@ class UnifiedConfigManager:
|
|
|
296
347
|
base_url=config_data.get("base_url"),
|
|
297
348
|
model_name=config_data.get("model_name"),
|
|
298
349
|
api_key=config_data.get("api_key"),
|
|
299
|
-
|
|
350
|
+
agent_type=config_data.get(
|
|
351
|
+
"agent_type", "glm"
|
|
352
|
+
), # 默认 'glm',兼容旧配置
|
|
353
|
+
agent_config_params=config_data.get("agent_config_params"),
|
|
354
|
+
default_max_steps=config_data.get("default_max_steps"),
|
|
300
355
|
decision_base_url=config_data.get("decision_base_url"),
|
|
301
356
|
decision_model_name=config_data.get("decision_model_name"),
|
|
302
357
|
decision_api_key=config_data.get("decision_api_key"),
|
|
@@ -327,7 +382,9 @@ class UnifiedConfigManager:
|
|
|
327
382
|
base_url: str,
|
|
328
383
|
model_name: str,
|
|
329
384
|
api_key: Optional[str] = None,
|
|
330
|
-
|
|
385
|
+
agent_type: Optional[str] = None,
|
|
386
|
+
agent_config_params: Optional[dict] = None,
|
|
387
|
+
default_max_steps: Optional[int] = None,
|
|
331
388
|
decision_base_url: Optional[str] = None,
|
|
332
389
|
decision_model_name: Optional[str] = None,
|
|
333
390
|
decision_api_key: Optional[str] = None,
|
|
@@ -340,10 +397,12 @@ class UnifiedConfigManager:
|
|
|
340
397
|
base_url: Base URL
|
|
341
398
|
model_name: 模型名称
|
|
342
399
|
api_key: API key(可选)
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
400
|
+
agent_type: Agent 类型(可选,如 "glm", "mai")
|
|
401
|
+
agent_config_params: Agent 特定配置参数(可选)
|
|
402
|
+
default_max_steps: 默认最大执行步数(可选)
|
|
403
|
+
decision_base_url: 决策模型 Base URL(可选)
|
|
404
|
+
decision_model_name: 决策模型名称(可选)
|
|
405
|
+
decision_api_key: 决策模型 API Key(可选)
|
|
347
406
|
merge_mode: 是否合并现有配置(True: 保留未提供的字段)
|
|
348
407
|
|
|
349
408
|
Returns:
|
|
@@ -354,20 +413,26 @@ class UnifiedConfigManager:
|
|
|
354
413
|
self._config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
355
414
|
|
|
356
415
|
# 准备新配置
|
|
357
|
-
new_config = {
|
|
416
|
+
new_config: dict[str, str | bool | int | dict | None] = {
|
|
358
417
|
"base_url": base_url,
|
|
359
418
|
"model_name": model_name,
|
|
360
419
|
}
|
|
361
420
|
|
|
362
421
|
if api_key:
|
|
363
422
|
new_config["api_key"] = api_key
|
|
364
|
-
if
|
|
365
|
-
new_config["
|
|
366
|
-
if
|
|
423
|
+
if agent_type is not None:
|
|
424
|
+
new_config["agent_type"] = agent_type
|
|
425
|
+
if agent_config_params is not None:
|
|
426
|
+
new_config["agent_config_params"] = agent_config_params
|
|
427
|
+
if default_max_steps is not None:
|
|
428
|
+
new_config["default_max_steps"] = default_max_steps
|
|
429
|
+
|
|
430
|
+
# 决策模型配置
|
|
431
|
+
if decision_base_url is not None:
|
|
367
432
|
new_config["decision_base_url"] = decision_base_url
|
|
368
|
-
if decision_model_name:
|
|
433
|
+
if decision_model_name is not None:
|
|
369
434
|
new_config["decision_model_name"] = decision_model_name
|
|
370
|
-
if decision_api_key:
|
|
435
|
+
if decision_api_key is not None:
|
|
371
436
|
new_config["decision_api_key"] = decision_api_key
|
|
372
437
|
|
|
373
438
|
# 合并模式:保留现有文件中未提供的字段
|
|
@@ -379,7 +444,9 @@ class UnifiedConfigManager:
|
|
|
379
444
|
# 保留未提供的字段
|
|
380
445
|
preserve_keys = [
|
|
381
446
|
"api_key",
|
|
382
|
-
"
|
|
447
|
+
"agent_type",
|
|
448
|
+
"agent_config_params",
|
|
449
|
+
"default_max_steps",
|
|
383
450
|
"decision_base_url",
|
|
384
451
|
"decision_model_name",
|
|
385
452
|
"decision_api_key",
|
|
@@ -467,7 +534,9 @@ class UnifiedConfigManager:
|
|
|
467
534
|
"base_url",
|
|
468
535
|
"model_name",
|
|
469
536
|
"api_key",
|
|
470
|
-
"
|
|
537
|
+
"agent_type",
|
|
538
|
+
"agent_config_params",
|
|
539
|
+
"default_max_steps",
|
|
471
540
|
"decision_base_url",
|
|
472
541
|
"decision_model_name",
|
|
473
542
|
"decision_api_key",
|
|
@@ -633,7 +702,9 @@ class UnifiedConfigManager:
|
|
|
633
702
|
"base_url": config.base_url,
|
|
634
703
|
"model_name": config.model_name,
|
|
635
704
|
"api_key": config.api_key,
|
|
636
|
-
"
|
|
705
|
+
"agent_type": config.agent_type,
|
|
706
|
+
"agent_config_params": config.agent_config_params,
|
|
707
|
+
"default_max_steps": config.default_max_steps,
|
|
637
708
|
"decision_base_url": config.decision_base_url,
|
|
638
709
|
"decision_model_name": config.decision_model_name,
|
|
639
710
|
"decision_api_key": config.decision_api_key,
|