autoglm-gui 1.4.0__py3-none-any.whl → 1.4.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/__main__.py +0 -4
- AutoGLM_GUI/adb_plus/qr_pair.py +8 -8
- AutoGLM_GUI/agents/__init__.py +20 -0
- AutoGLM_GUI/agents/factory.py +160 -0
- AutoGLM_GUI/agents/mai_adapter.py +627 -0
- AutoGLM_GUI/agents/protocols.py +23 -0
- AutoGLM_GUI/api/__init__.py +48 -7
- AutoGLM_GUI/api/agents.py +61 -17
- AutoGLM_GUI/api/devices.py +12 -18
- AutoGLM_GUI/api/dual_model.py +15 -9
- AutoGLM_GUI/api/health.py +13 -0
- AutoGLM_GUI/api/layered_agent.py +239 -166
- AutoGLM_GUI/api/mcp.py +11 -10
- AutoGLM_GUI/api/version.py +23 -10
- AutoGLM_GUI/api/workflows.py +2 -1
- AutoGLM_GUI/config_manager.py +55 -1
- AutoGLM_GUI/device_adapter.py +263 -0
- AutoGLM_GUI/device_protocol.py +266 -0
- AutoGLM_GUI/devices/__init__.py +49 -0
- AutoGLM_GUI/devices/adb_device.py +205 -0
- AutoGLM_GUI/devices/mock_device.py +183 -0
- AutoGLM_GUI/devices/remote_device.py +172 -0
- AutoGLM_GUI/dual_model/decision_model.py +4 -4
- AutoGLM_GUI/exceptions.py +3 -3
- AutoGLM_GUI/mai_ui_adapter/agent_wrapper.py +2 -2
- AutoGLM_GUI/metrics.py +13 -20
- AutoGLM_GUI/phone_agent_manager.py +219 -134
- AutoGLM_GUI/phone_agent_patches.py +2 -1
- AutoGLM_GUI/platform_utils.py +5 -2
- AutoGLM_GUI/schemas.py +47 -0
- AutoGLM_GUI/scrcpy_stream.py +17 -13
- AutoGLM_GUI/server.py +3 -1
- AutoGLM_GUI/socketio_server.py +16 -4
- AutoGLM_GUI/state.py +10 -30
- AutoGLM_GUI/static/assets/{about-DeclntHg.js → about-_XNhzQZX.js} +1 -1
- AutoGLM_GUI/static/assets/chat-DwJpiAWf.js +126 -0
- AutoGLM_GUI/static/assets/{dialog-BfdcBs1x.js → dialog-B3uW4T8V.js} +3 -3
- AutoGLM_GUI/static/assets/index-Cpv2gSF1.css +1 -0
- AutoGLM_GUI/static/assets/{index-zQ4KKDHt.js → index-Cy8TmmHV.js} +1 -1
- AutoGLM_GUI/static/assets/{index-DHF1NZh0.js → index-UYYauTly.js} +6 -6
- AutoGLM_GUI/static/assets/{workflows-xiplap-r.js → workflows-Du_de-dt.js} +1 -1
- AutoGLM_GUI/static/index.html +2 -2
- AutoGLM_GUI/types.py +125 -0
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.4.1.dist-info}/METADATA +83 -4
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.4.1.dist-info}/RECORD +54 -37
- 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/config.py +0 -23
- AutoGLM_GUI/static/assets/chat-Iut2yhSw.js +0 -125
- AutoGLM_GUI/static/assets/index-5hCCwHA7.css +0 -1
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.4.1.dist-info}/WHEEL +0 -0
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.4.1.dist-info}/entry_points.txt +0 -0
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.4.1.dist-info}/licenses/LICENSE +0 -0
AutoGLM_GUI/api/__init__.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""FastAPI application factory and route registration."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import os
|
|
4
5
|
import sys
|
|
5
6
|
from contextlib import asynccontextmanager
|
|
6
7
|
from importlib.resources import files
|
|
@@ -12,6 +13,7 @@ from fastapi.responses import FileResponse
|
|
|
12
13
|
from fastapi.staticfiles import StaticFiles
|
|
13
14
|
|
|
14
15
|
from AutoGLM_GUI.adb_plus.qr_pair import qr_pairing_manager
|
|
16
|
+
from AutoGLM_GUI.logger import logger
|
|
15
17
|
from AutoGLM_GUI.version import APP_VERSION
|
|
16
18
|
|
|
17
19
|
from . import (
|
|
@@ -19,6 +21,7 @@ from . import (
|
|
|
19
21
|
control,
|
|
20
22
|
devices,
|
|
21
23
|
dual_model,
|
|
24
|
+
health,
|
|
22
25
|
layered_agent,
|
|
23
26
|
mcp,
|
|
24
27
|
media,
|
|
@@ -28,11 +31,30 @@ from . import (
|
|
|
28
31
|
)
|
|
29
32
|
|
|
30
33
|
|
|
34
|
+
# TODO:应该要支持运行时动态切换设备
|
|
35
|
+
def _maybe_inject_remote_device() -> None:
|
|
36
|
+
if remote_base_url := os.getenv("REMOTE_DEVICE_BASE_URL"):
|
|
37
|
+
from AutoGLM_GUI.device_adapter import inject_device_protocol
|
|
38
|
+
from AutoGLM_GUI.devices.remote_device import RemoteDevice
|
|
39
|
+
|
|
40
|
+
def get_remote_device(device_id: str | None):
|
|
41
|
+
return RemoteDevice(device_id or "mock_device_001", remote_base_url)
|
|
42
|
+
|
|
43
|
+
inject_device_protocol(get_remote_device)
|
|
44
|
+
logger.info(f"Remote device mode enabled: connecting to {remote_base_url}")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _get_cors_origins() -> list[str]:
|
|
48
|
+
cors_origins_str = os.getenv("AUTOGLM_CORS_ORIGINS", "http://localhost:3000")
|
|
49
|
+
if cors_origins_str == "*":
|
|
50
|
+
return ["*"]
|
|
51
|
+
return [origin.strip() for origin in cors_origins_str.split(",") if origin.strip()]
|
|
52
|
+
|
|
53
|
+
|
|
31
54
|
def _get_static_dir() -> Path | None:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
bundled_static = Path(sys._MEIPASS) / "AutoGLM_GUI" / "static"
|
|
55
|
+
meipass = getattr(sys, "_MEIPASS", None)
|
|
56
|
+
if meipass:
|
|
57
|
+
bundled_static = Path(meipass) / "AutoGLM_GUI" / "static"
|
|
36
58
|
if bundled_static.exists():
|
|
37
59
|
return bundled_static
|
|
38
60
|
|
|
@@ -55,6 +77,9 @@ def _get_static_dir() -> Path | None:
|
|
|
55
77
|
def create_app() -> FastAPI:
|
|
56
78
|
"""Build the FastAPI app with routers and static assets."""
|
|
57
79
|
|
|
80
|
+
# Inject RemoteDevice if REMOTE_DEVICE_BASE_URL is set
|
|
81
|
+
_maybe_inject_remote_device()
|
|
82
|
+
|
|
58
83
|
# Create MCP ASGI app
|
|
59
84
|
mcp_app = mcp.get_mcp_asgi_app()
|
|
60
85
|
|
|
@@ -83,13 +108,14 @@ def create_app() -> FastAPI:
|
|
|
83
108
|
|
|
84
109
|
app.add_middleware(
|
|
85
110
|
CORSMiddleware,
|
|
86
|
-
allow_origins=
|
|
111
|
+
allow_origins=_get_cors_origins(),
|
|
87
112
|
allow_credentials=True,
|
|
88
113
|
allow_methods=["*"],
|
|
89
114
|
allow_headers=["*"],
|
|
90
115
|
)
|
|
91
116
|
|
|
92
117
|
app.include_router(agents.router)
|
|
118
|
+
app.include_router(health.router)
|
|
93
119
|
app.include_router(layered_agent.router)
|
|
94
120
|
app.include_router(devices.router)
|
|
95
121
|
app.include_router(control.router)
|
|
@@ -106,14 +132,29 @@ def create_app() -> FastAPI:
|
|
|
106
132
|
if static_dir is not None and static_dir.exists():
|
|
107
133
|
assets_dir = static_dir / "assets"
|
|
108
134
|
if assets_dir.exists():
|
|
135
|
+
# Vite builds assets with content hashes, so we can cache them long-term
|
|
109
136
|
app.mount("/assets", StaticFiles(directory=assets_dir), name="assets")
|
|
110
137
|
|
|
111
138
|
# Define SPA serving function
|
|
112
139
|
async def serve_spa(full_path: str) -> FileResponse:
|
|
113
140
|
file_path = static_dir / full_path
|
|
114
141
|
if file_path.is_file():
|
|
115
|
-
return FileResponse(
|
|
116
|
-
|
|
142
|
+
return FileResponse(
|
|
143
|
+
file_path,
|
|
144
|
+
headers={
|
|
145
|
+
"Cache-Control": "no-cache, no-store, must-revalidate",
|
|
146
|
+
"Pragma": "no-cache",
|
|
147
|
+
"Expires": "0",
|
|
148
|
+
},
|
|
149
|
+
)
|
|
150
|
+
return FileResponse(
|
|
151
|
+
static_dir / "index.html",
|
|
152
|
+
headers={
|
|
153
|
+
"Cache-Control": "no-cache, no-store, must-revalidate",
|
|
154
|
+
"Pragma": "no-cache",
|
|
155
|
+
"Expires": "0",
|
|
156
|
+
},
|
|
157
|
+
)
|
|
117
158
|
|
|
118
159
|
# Add catch-all route for SPA (handles all non-API routes)
|
|
119
160
|
app.add_api_route(
|
AutoGLM_GUI/api/agents.py
CHANGED
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
import json
|
|
4
4
|
import queue
|
|
5
5
|
import threading
|
|
6
|
-
from typing import Any
|
|
7
6
|
|
|
8
7
|
from fastapi import APIRouter, HTTPException
|
|
9
8
|
from fastapi.responses import StreamingResponse
|
|
9
|
+
from phone_agent.agent import StepResult
|
|
10
10
|
from pydantic import ValidationError
|
|
11
11
|
|
|
12
|
-
from AutoGLM_GUI.config import config
|
|
13
12
|
from AutoGLM_GUI.logger import logger
|
|
14
13
|
from AutoGLM_GUI.phone_agent_patches import apply_patches
|
|
15
14
|
from AutoGLM_GUI.schemas import (
|
|
@@ -91,9 +90,12 @@ def _initialize_agent_with_config(
|
|
|
91
90
|
logger.info(f"Agent initialized successfully for device {device_id}")
|
|
92
91
|
|
|
93
92
|
|
|
93
|
+
SSEPayload = dict[str, str | int | bool | None | dict]
|
|
94
|
+
|
|
95
|
+
|
|
94
96
|
def _create_sse_event(
|
|
95
|
-
event_type: str, data:
|
|
96
|
-
) ->
|
|
97
|
+
event_type: str, data: SSEPayload, role: str = "assistant"
|
|
98
|
+
) -> SSEPayload:
|
|
97
99
|
"""Create an SSE event with standardized fields including role."""
|
|
98
100
|
event_data = {"type": event_type, "role": role, **data}
|
|
99
101
|
return event_data
|
|
@@ -116,11 +118,17 @@ def init_agent(request: InitRequest) -> dict:
|
|
|
116
118
|
# 热重载配置文件(支持运行时手动修改)
|
|
117
119
|
config_manager.load_file_config()
|
|
118
120
|
config_manager.sync_to_env()
|
|
119
|
-
config.refresh_from_env()
|
|
120
121
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
# 获取有效配置(已合并 CLI > ENV > FILE > DEFAULT)
|
|
123
|
+
effective_config = config_manager.get_effective_config()
|
|
124
|
+
|
|
125
|
+
# 优先级:请求参数 > 有效配置
|
|
126
|
+
base_url = req_model_config.base_url or effective_config.base_url
|
|
127
|
+
api_key = req_model_config.api_key or effective_config.api_key
|
|
128
|
+
model_name = req_model_config.model_name or effective_config.model_name
|
|
129
|
+
|
|
130
|
+
# 获取配置的默认最大步数
|
|
131
|
+
max_steps = effective_config.default_max_steps
|
|
124
132
|
|
|
125
133
|
if not base_url:
|
|
126
134
|
raise HTTPException(
|
|
@@ -139,7 +147,7 @@ def init_agent(request: InitRequest) -> dict:
|
|
|
139
147
|
)
|
|
140
148
|
|
|
141
149
|
agent_config = AgentConfig(
|
|
142
|
-
max_steps=
|
|
150
|
+
max_steps=max_steps,
|
|
143
151
|
device_id=device_id,
|
|
144
152
|
lang=req_agent_config.lang,
|
|
145
153
|
system_prompt=req_agent_config.system_prompt,
|
|
@@ -148,7 +156,35 @@ def init_agent(request: InitRequest) -> dict:
|
|
|
148
156
|
|
|
149
157
|
# Initialize agent (includes ADB Keyboard setup)
|
|
150
158
|
try:
|
|
151
|
-
|
|
159
|
+
# Setup ADB Keyboard (common for all agents)
|
|
160
|
+
_setup_adb_keyboard(device_id)
|
|
161
|
+
|
|
162
|
+
# Use agent factory to create agent
|
|
163
|
+
from AutoGLM_GUI.phone_agent_manager import PhoneAgentManager
|
|
164
|
+
|
|
165
|
+
manager = PhoneAgentManager.get_instance()
|
|
166
|
+
|
|
167
|
+
# Initialize agent using factory pattern
|
|
168
|
+
from typing import cast
|
|
169
|
+
|
|
170
|
+
from AutoGLM_GUI.types import AgentSpecificConfig
|
|
171
|
+
|
|
172
|
+
agent_config_params = cast(
|
|
173
|
+
AgentSpecificConfig, request.agent_config_params or {}
|
|
174
|
+
)
|
|
175
|
+
manager.initialize_agent_with_factory(
|
|
176
|
+
device_id=device_id,
|
|
177
|
+
agent_type=request.agent_type,
|
|
178
|
+
model_config=model_config,
|
|
179
|
+
agent_config=agent_config,
|
|
180
|
+
agent_specific_config=agent_config_params,
|
|
181
|
+
takeover_callback=non_blocking_takeover,
|
|
182
|
+
force=request.force,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
logger.info(
|
|
186
|
+
f"Agent of type '{request.agent_type}' initialized for device {device_id}"
|
|
187
|
+
)
|
|
152
188
|
except Exception as e:
|
|
153
189
|
logger.error(f"Failed to initialize agent: {e}")
|
|
154
190
|
raise HTTPException(status_code=500, detail=str(e))
|
|
@@ -157,6 +193,7 @@ def init_agent(request: InitRequest) -> dict:
|
|
|
157
193
|
"success": True,
|
|
158
194
|
"device_id": device_id,
|
|
159
195
|
"message": f"Agent initialized for device {device_id}",
|
|
196
|
+
"agent_type": request.agent_type,
|
|
160
197
|
}
|
|
161
198
|
|
|
162
199
|
|
|
@@ -207,12 +244,12 @@ def chat_stream(request: ChatRequest):
|
|
|
207
244
|
)
|
|
208
245
|
|
|
209
246
|
def event_generator():
|
|
210
|
-
"""SSE 事件生成器."""
|
|
211
247
|
threads: list[threading.Thread] = []
|
|
248
|
+
stop_event: threading.Event | None = None
|
|
212
249
|
|
|
213
250
|
try:
|
|
214
251
|
# 创建事件队列用于 agent → SSE 通信
|
|
215
|
-
event_queue: queue.Queue[tuple[str,
|
|
252
|
+
event_queue: queue.Queue[tuple[str, SSEPayload | None]] = queue.Queue()
|
|
216
253
|
|
|
217
254
|
# 思考块回调
|
|
218
255
|
def on_thinking_chunk(chunk: str):
|
|
@@ -231,8 +268,8 @@ def chat_stream(request: ChatRequest):
|
|
|
231
268
|
return
|
|
232
269
|
|
|
233
270
|
# 在线程中运行 agent 步骤
|
|
234
|
-
step_result: list[
|
|
235
|
-
error_result: list[
|
|
271
|
+
step_result: list[StepResult | None] = [None]
|
|
272
|
+
error_result: list[Exception | None] = [None]
|
|
236
273
|
|
|
237
274
|
def run_step(is_first: bool = True, task: str | None = None):
|
|
238
275
|
try:
|
|
@@ -277,6 +314,9 @@ def chat_stream(request: ChatRequest):
|
|
|
277
314
|
raise error_result[0]
|
|
278
315
|
|
|
279
316
|
result = step_result[0]
|
|
317
|
+
if result is None:
|
|
318
|
+
raise RuntimeError("step_result is None after step_done")
|
|
319
|
+
|
|
280
320
|
event_data = _create_sse_event(
|
|
281
321
|
"step",
|
|
282
322
|
{
|
|
@@ -349,8 +389,7 @@ def chat_stream(request: ChatRequest):
|
|
|
349
389
|
yield "event: error\n"
|
|
350
390
|
yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n"
|
|
351
391
|
finally:
|
|
352
|
-
|
|
353
|
-
if "stop_event" in locals():
|
|
392
|
+
if stop_event is not None:
|
|
354
393
|
stop_event.set()
|
|
355
394
|
|
|
356
395
|
# 等待线程完成(带超时)
|
|
@@ -460,6 +499,9 @@ def get_config_endpoint() -> ConfigResponse:
|
|
|
460
499
|
decision_api_key=effective_config.decision_api_key
|
|
461
500
|
if effective_config.decision_api_key
|
|
462
501
|
else "",
|
|
502
|
+
agent_type=effective_config.agent_type,
|
|
503
|
+
agent_config_params=effective_config.agent_config_params,
|
|
504
|
+
default_max_steps=effective_config.default_max_steps,
|
|
463
505
|
conflicts=[
|
|
464
506
|
{
|
|
465
507
|
"field": c.field,
|
|
@@ -496,6 +538,9 @@ def save_config_endpoint(request: ConfigSaveRequest) -> dict:
|
|
|
496
538
|
decision_base_url=request.decision_base_url,
|
|
497
539
|
decision_model_name=request.decision_model_name,
|
|
498
540
|
decision_api_key=request.decision_api_key,
|
|
541
|
+
agent_type=request.agent_type,
|
|
542
|
+
agent_config_params=request.agent_config_params,
|
|
543
|
+
default_max_steps=request.default_max_steps,
|
|
499
544
|
merge_mode=True,
|
|
500
545
|
)
|
|
501
546
|
|
|
@@ -504,7 +549,6 @@ def save_config_endpoint(request: ConfigSaveRequest) -> dict:
|
|
|
504
549
|
|
|
505
550
|
# 同步到环境变量
|
|
506
551
|
config_manager.sync_to_env()
|
|
507
|
-
config.refresh_from_env()
|
|
508
552
|
|
|
509
553
|
# 检测冲突并返回警告
|
|
510
554
|
conflicts = config_manager.detect_conflicts()
|
AutoGLM_GUI/api/devices.py
CHANGED
|
@@ -15,6 +15,7 @@ from AutoGLM_GUI.logger import logger
|
|
|
15
15
|
|
|
16
16
|
from AutoGLM_GUI.schemas import (
|
|
17
17
|
DeviceListResponse,
|
|
18
|
+
DeviceResponse,
|
|
18
19
|
WiFiConnectRequest,
|
|
19
20
|
WiFiConnectResponse,
|
|
20
21
|
WiFiDisconnectRequest,
|
|
@@ -32,29 +33,16 @@ from AutoGLM_GUI.schemas import (
|
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
def _build_device_response_with_agent(
|
|
35
|
-
device: ManagedDevice, agent_manager: PhoneAgentManager
|
|
36
|
-
) ->
|
|
37
|
-
"""组合设备信息和 Agent 状态(API 层职责)。
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
device: ManagedDevice 实例
|
|
41
|
-
agent_manager: PhoneAgentManager 实例
|
|
42
|
-
|
|
43
|
-
Returns:
|
|
44
|
-
dict: 完整的设备响应,匹配 DeviceResponse schema
|
|
45
|
-
"""
|
|
46
|
-
# 获取纯设备信息
|
|
36
|
+
device: "ManagedDevice", agent_manager: "PhoneAgentManager"
|
|
37
|
+
) -> DeviceResponse:
|
|
47
38
|
response = device.to_dict()
|
|
48
|
-
|
|
49
|
-
# 通过 serial 查找 Agent(支持连接切换)
|
|
50
39
|
agent_device_id = agent_manager.find_agent_by_serial(device.serial)
|
|
51
40
|
|
|
52
41
|
if agent_device_id:
|
|
53
42
|
metadata = agent_manager.get_metadata(agent_device_id)
|
|
54
|
-
|
|
55
43
|
if metadata:
|
|
56
44
|
response["agent"] = {
|
|
57
|
-
"state": metadata.state
|
|
45
|
+
"state": metadata.state, # AgentState is str, Enum, already a string
|
|
58
46
|
"created_at": metadata.created_at,
|
|
59
47
|
"last_used": metadata.last_used,
|
|
60
48
|
"error_message": metadata.error_message,
|
|
@@ -65,7 +53,7 @@ def _build_device_response_with_agent(
|
|
|
65
53
|
else:
|
|
66
54
|
response["agent"] = None
|
|
67
55
|
|
|
68
|
-
return response
|
|
56
|
+
return DeviceResponse.model_validate(response)
|
|
69
57
|
|
|
70
58
|
|
|
71
59
|
router = APIRouter()
|
|
@@ -97,9 +85,15 @@ def list_devices() -> DeviceListResponse:
|
|
|
97
85
|
|
|
98
86
|
@router.post("/api/devices/connect_wifi", response_model=WiFiConnectResponse)
|
|
99
87
|
def connect_wifi(request: WiFiConnectRequest) -> WiFiConnectResponse:
|
|
100
|
-
"""从 USB 启用 TCP/IP 并连接到 WiFi。"""
|
|
101
88
|
from AutoGLM_GUI.device_manager import DeviceManager
|
|
102
89
|
|
|
90
|
+
if not request.device_id:
|
|
91
|
+
return WiFiConnectResponse(
|
|
92
|
+
success=False,
|
|
93
|
+
message="device_id is required",
|
|
94
|
+
error="device_not_found",
|
|
95
|
+
)
|
|
96
|
+
|
|
103
97
|
device_manager = DeviceManager.get_instance()
|
|
104
98
|
success, message, wifi_id = device_manager.connect_wifi(
|
|
105
99
|
device_id=request.device_id,
|
AutoGLM_GUI/api/dual_model.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""双模型协作API端点"""
|
|
2
2
|
|
|
3
3
|
import threading
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Optional
|
|
5
5
|
|
|
6
6
|
from fastapi import APIRouter, HTTPException
|
|
7
7
|
from fastapi.responses import StreamingResponse
|
|
@@ -67,7 +67,7 @@ class DualModelStatusResponse(BaseModel):
|
|
|
67
67
|
@router.post("/init")
|
|
68
68
|
def init_dual_model(request: DualModelInitRequest) -> dict:
|
|
69
69
|
"""初始化双模型Agent"""
|
|
70
|
-
from AutoGLM_GUI.
|
|
70
|
+
from AutoGLM_GUI.config_manager import config_manager
|
|
71
71
|
from AutoGLM_GUI.phone_agent_manager import PhoneAgentManager
|
|
72
72
|
|
|
73
73
|
device_id = request.device_id
|
|
@@ -86,10 +86,16 @@ def init_dual_model(request: DualModelInitRequest) -> dict:
|
|
|
86
86
|
status_code=400, detail="设备尚未初始化单模型Agent,请先调用 /api/init"
|
|
87
87
|
)
|
|
88
88
|
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
# 获取有效配置
|
|
90
|
+
effective_config = config_manager.get_effective_config()
|
|
91
|
+
|
|
92
|
+
# 获取配置的默认最大步数
|
|
93
|
+
max_steps = effective_config.default_max_steps
|
|
94
|
+
|
|
95
|
+
# 获取视觉模型配置(优先级:请求参数 > 有效配置)
|
|
96
|
+
vision_base_url = request.vision_base_url or effective_config.base_url
|
|
97
|
+
vision_api_key = request.vision_api_key or effective_config.api_key
|
|
98
|
+
vision_model_name = request.vision_model_name or effective_config.model_name
|
|
93
99
|
|
|
94
100
|
if not vision_base_url:
|
|
95
101
|
raise HTTPException(status_code=400, detail="视觉模型base_url未配置")
|
|
@@ -114,7 +120,7 @@ def init_dual_model(request: DualModelInitRequest) -> dict:
|
|
|
114
120
|
decision_config=decision_config,
|
|
115
121
|
vision_config=vision_config,
|
|
116
122
|
device_id=device_id,
|
|
117
|
-
max_steps=
|
|
123
|
+
max_steps=max_steps,
|
|
118
124
|
thinking_mode=thinking_mode,
|
|
119
125
|
)
|
|
120
126
|
|
|
@@ -164,8 +170,8 @@ def dual_model_chat_stream(request: DualModelChatRequest):
|
|
|
164
170
|
logger.info(f"开始双模型任务: {request.message[:50]}...")
|
|
165
171
|
|
|
166
172
|
# 在后台线程运行Agent
|
|
167
|
-
result_holder: list[
|
|
168
|
-
error_holder: list[
|
|
173
|
+
result_holder: list[dict | None] = [None]
|
|
174
|
+
error_holder: list[Exception | None] = [None]
|
|
169
175
|
|
|
170
176
|
def run_agent():
|
|
171
177
|
try:
|
|
@@ -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
|
+
}
|