autoglm-gui 1.5.3__tar.gz → 1.5.5__tar.gz

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.
Files changed (121) hide show
  1. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/__main__.py +33 -7
  2. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/glm/async_agent.py +64 -99
  3. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/protocols.py +3 -14
  4. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/__init__.py +16 -0
  5. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/agents.py +0 -1
  6. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/logger.py +3 -2
  7. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/about-DTrVqEQH.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/about-BwLRPh96.js +1 -1
  8. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/alert-dialog-B2KxPLtZ.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/alert-dialog-BvDNaR9v.js +1 -1
  9. autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/chat-DAmrsouh.js +129 -0
  10. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/circle-alert-vnNxOaxv.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/circle-alert-C8768IhH.js +1 -1
  11. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/dialog-Cuw3N8_F.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/dialog-IM0Ds7Lf.js +2 -2
  12. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/eye-JD1jbm99.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/eye-BWBwz8sy.js +1 -1
  13. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/history-CobYdXju.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/history-BkQlPjpV.js +1 -1
  14. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/index-y1vOOBHH.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/index-B0fISVXF.js +1 -1
  15. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/index-BzP-Te33.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/index-CH4jPveL.js +8 -8
  16. autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/index-DSIMVL8V.css +1 -0
  17. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/label-BpCMrXj_.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/label-CmQFo_IT.js +1 -1
  18. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/logs-BcsSAeol.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/logs-ChcSA2r_.js +1 -1
  19. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/popover-BHbCs5Wl.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/popover-BnpBfSOh.js +1 -1
  20. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/scheduled-tasks-WvtmRsex.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/scheduled-tasks-BwgoPEdP.js +1 -1
  21. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/textarea-B84jf3cE.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/textarea-BlKvI11g.js +1 -1
  22. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/workflows-DhBpqdz_.js → autoglm_gui-1.5.5/AutoGLM_GUI/static/assets/workflows-CRq1fJf5.js +1 -1
  23. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/static/index.html +2 -2
  24. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/PKG-INFO +7 -5
  25. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/README.md +6 -4
  26. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/pyproject.toml +1 -1
  27. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/chat-BkrVbc3X.js +0 -129
  28. autoglm_gui-1.5.3/AutoGLM_GUI/static/assets/index-CV7jGxGm.css +0 -1
  29. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/.gitignore +0 -0
  30. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/__init__.py +0 -0
  31. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/actions/__init__.py +0 -0
  32. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/actions/handler.py +0 -0
  33. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/actions/types.py +0 -0
  34. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb/__init__.py +0 -0
  35. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb/apps.py +0 -0
  36. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb/connection.py +0 -0
  37. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb/device.py +0 -0
  38. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb/input.py +0 -0
  39. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb/screenshot.py +0 -0
  40. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb/timing.py +0 -0
  41. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/__init__.py +0 -0
  42. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/device.py +0 -0
  43. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/ip.py +0 -0
  44. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/keyboard_installer.py +0 -0
  45. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/mdns.py +0 -0
  46. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/pair.py +0 -0
  47. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/qr_pair.py +0 -0
  48. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/screenshot.py +0 -0
  49. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/serial.py +0 -0
  50. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/touch.py +0 -0
  51. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/adb_plus/version.py +0 -0
  52. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/__init__.py +0 -0
  53. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/events.py +0 -0
  54. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/factory.py +0 -0
  55. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/glm/__init__.py +0 -0
  56. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/glm/agent.py +0 -0
  57. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/glm/message_builder.py +0 -0
  58. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/glm/parser.py +0 -0
  59. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/glm/prompts_en.py +0 -0
  60. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/glm/prompts_zh.py +0 -0
  61. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/mai/__init__.py +0 -0
  62. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/mai/agent.py +0 -0
  63. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/mai/parser.py +0 -0
  64. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/mai/prompts.py +0 -0
  65. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/mai/traj_memory.py +0 -0
  66. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/agents/stream_runner.py +0 -0
  67. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/control.py +0 -0
  68. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/devices.py +0 -0
  69. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/health.py +0 -0
  70. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/history.py +0 -0
  71. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/layered_agent.py +0 -0
  72. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/mcp.py +0 -0
  73. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/media.py +0 -0
  74. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/metrics.py +0 -0
  75. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/scheduled_tasks.py +0 -0
  76. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/version.py +0 -0
  77. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/api/workflows.py +0 -0
  78. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/config.py +0 -0
  79. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/config_manager.py +0 -0
  80. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/device_manager.py +0 -0
  81. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/device_metadata_manager.py +0 -0
  82. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/device_protocol.py +0 -0
  83. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/devices/__init__.py +0 -0
  84. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/devices/adb_device.py +0 -0
  85. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/devices/mock_device.py +0 -0
  86. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/devices/remote_device.py +0 -0
  87. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/exceptions.py +0 -0
  88. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/history_manager.py +0 -0
  89. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/i18n.py +0 -0
  90. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/metrics.py +0 -0
  91. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/model/__init__.py +0 -0
  92. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/model/message_builder.py +0 -0
  93. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/model/types.py +0 -0
  94. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/models/__init__.py +0 -0
  95. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/models/history.py +0 -0
  96. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/models/scheduled_task.py +0 -0
  97. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/parsers/__init__.py +0 -0
  98. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/parsers/base.py +0 -0
  99. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/parsers/phone_parser.py +0 -0
  100. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/phone_agent_manager.py +0 -0
  101. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/platform_utils.py +0 -0
  102. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/prompt_config.py +0 -0
  103. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/prompts/__init__.py +0 -0
  104. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/prompts.py +0 -0
  105. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/scheduler_manager.py +0 -0
  106. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/schemas.py +0 -0
  107. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/scrcpy_protocol.py +0 -0
  108. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/scrcpy_stream.py +0 -0
  109. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/server.py +0 -0
  110. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/socketio_server.py +0 -0
  111. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/state.py +0 -0
  112. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/static/assets/logo-Cyfm06Ym.png +0 -0
  113. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/static/assets/worker-D6BRitjy.js +0 -0
  114. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/static/favicon.ico +0 -0
  115. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/static/logo-192.png +0 -0
  116. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/static/logo-512.png +0 -0
  117. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/types.py +0 -0
  118. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/version.py +0 -0
  119. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/AutoGLM_GUI/workflow_manager.py +0 -0
  120. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/LICENSE +0 -0
  121. {autoglm_gui-1.5.3 → autoglm_gui-1.5.5}/scrcpy-server-v3.3.3 +0 -0
@@ -76,6 +76,39 @@ def open_browser(
76
76
 
77
77
  def main() -> None:
78
78
  """Start the AutoGLM-GUI server."""
79
+ # Configure logging BEFORE any other imports to ensure DEBUG level from the start
80
+ # This is especially important for --reload mode where subprocess reimports modules
81
+ import os
82
+ import sys
83
+
84
+ # Parse args early to get log level
85
+ early_parser = argparse.ArgumentParser(add_help=False)
86
+ early_parser.add_argument(
87
+ "--log-level",
88
+ choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
89
+ default="INFO",
90
+ )
91
+ early_parser.add_argument(
92
+ "--log-file", default="logs/autoglm_{time:YYYY-MM-DD}.log"
93
+ )
94
+ early_parser.add_argument("--no-log-file", action="store_true")
95
+ early_args, _ = early_parser.parse_known_args()
96
+
97
+ # Set environment variable for reload mode (subprocess will read this)
98
+ os.environ["AUTOGLM_LOG_LEVEL"] = early_args.log_level
99
+ if early_args.no_log_file:
100
+ os.environ["AUTOGLM_NO_LOG_FILE"] = "1"
101
+ else:
102
+ os.environ["AUTOGLM_LOG_FILE"] = early_args.log_file
103
+
104
+ # Import and configure logger FIRST
105
+ from AutoGLM_GUI.logger import configure_logger
106
+
107
+ configure_logger(
108
+ console_level=early_args.log_level,
109
+ log_file=None if early_args.no_log_file else early_args.log_file,
110
+ )
111
+
79
112
  parser = argparse.ArgumentParser(
80
113
  description="AutoGLM-GUI - Web GUI for AutoGLM Phone Agent"
81
114
  )
@@ -163,13 +196,6 @@ def main() -> None:
163
196
 
164
197
  from AutoGLM_GUI import server
165
198
  from AutoGLM_GUI.config_manager import config_manager
166
- from AutoGLM_GUI.logger import configure_logger
167
-
168
- # Configure logging system
169
- configure_logger(
170
- console_level=args.log_level,
171
- log_file=None if args.no_log_file else args.log_file,
172
- )
173
199
 
174
200
  # ==================== 配置系统初始化 ====================
175
201
  # 使用统一配置管理器(四层优先级:CLI > ENV > FILE > DEFAULT)
@@ -8,7 +8,8 @@ from typing import Any, AsyncIterator, Callable
8
8
  from openai import AsyncOpenAI
9
9
 
10
10
  from AutoGLM_GUI.actions import ActionHandler, ActionResult
11
- from AutoGLM_GUI.config import AgentConfig, ModelConfig, StepResult
11
+ from AutoGLM_GUI.agents.protocols import AsyncAgent
12
+ from AutoGLM_GUI.config import AgentConfig, ModelConfig
12
13
  from AutoGLM_GUI.device_protocol import DeviceProtocol
13
14
  from AutoGLM_GUI.logger import logger
14
15
  from AutoGLM_GUI.prompt_config import get_messages, get_system_prompt
@@ -17,7 +18,7 @@ from .message_builder import MessageBuilder
17
18
  from .parser import GLMParser
18
19
 
19
20
 
20
- class AsyncGLMAgent:
21
+ class AsyncGLMAgent(AsyncAgent):
21
22
  """异步 GLM Agent 实现。
22
23
 
23
24
  核心特性:
@@ -61,8 +62,18 @@ class AsyncGLMAgent:
61
62
  # 取消机制
62
63
  self._cancel_event = asyncio.Event()
63
64
 
65
+ # 初始化 system prompt(Agent 一创建就有"人格")
66
+ system_prompt = self.agent_config.system_prompt
67
+ if system_prompt is None:
68
+ system_prompt = get_system_prompt(self.agent_config.lang)
69
+
70
+ # 保存初始 system message 用于 reset()
71
+ self._initial_system_message = MessageBuilder.create_system_message(
72
+ system_prompt
73
+ )
74
+
64
75
  # 状态
65
- self._context: list[dict[str, Any]] = []
76
+ self._context: list[dict[str, Any]] = [self._initial_system_message]
66
77
  self._step_count = 0
67
78
  self._is_running = False
68
79
 
@@ -82,35 +93,46 @@ class AsyncGLMAgent:
82
93
  - "cancelled": {"message": str}
83
94
  - "error": {"message": str}
84
95
  """
85
- self._context = []
86
- self._step_count = 0
87
96
  self._is_running = True
88
97
  self._cancel_event.clear()
89
98
 
90
99
  try:
91
- # 首步执行
92
- async for event in self._execute_step_async(task, is_first=True):
93
- yield event
100
+ # ===== 初始化阶段:添加首次用户输入 =====
101
+ try:
102
+ screenshot = await asyncio.to_thread(self.device.get_screenshot)
103
+ current_app = await asyncio.to_thread(self.device.get_current_app)
104
+ except Exception as e:
105
+ logger.error(f"Failed to get device info during initialization: {e}")
106
+ yield {
107
+ "type": "error",
108
+ "data": {"message": f"Device error: {e}"},
109
+ }
110
+ yield {
111
+ "type": "done",
112
+ "data": {
113
+ "message": f"Device error: {e}",
114
+ "steps": 0,
115
+ "success": False,
116
+ },
117
+ }
118
+ return
94
119
 
95
- # 检查是否完成
96
- if event["type"] == "step" and event["data"].get("finished"):
97
- yield {
98
- "type": "done",
99
- "data": {
100
- "message": event["data"].get("message", "Task completed"),
101
- "steps": self._step_count,
102
- "success": event["data"].get("success", True),
103
- },
104
- }
105
- return
120
+ screen_info = MessageBuilder.build_screen_info(current_app)
121
+ initial_message = f"{task}\n\n** Screen Info **\n\n{screen_info}"
122
+
123
+ self._context.append(
124
+ MessageBuilder.create_user_message(
125
+ text=initial_message, image_base64=screenshot.base64_data
126
+ )
127
+ )
106
128
 
107
- # 后续步骤
129
+ # ===== 执行阶段:循环执行步骤 =====
108
130
  while self._step_count < self.agent_config.max_steps and self._is_running:
109
131
  # 检查取消
110
132
  if self._cancel_event.is_set():
111
133
  raise asyncio.CancelledError()
112
134
 
113
- async for event in self._execute_step_async(None, is_first=False):
135
+ async for event in self._execute_step_async():
114
136
  yield event
115
137
 
116
138
  # 检查是否完成
@@ -147,21 +169,19 @@ class AsyncGLMAgent:
147
169
  finally:
148
170
  self._is_running = False
149
171
 
150
- async def _execute_step_async(
151
- self, user_prompt: str | None, is_first: bool
152
- ) -> AsyncIterator[dict[str, Any]]:
172
+ async def _execute_step_async(self) -> AsyncIterator[dict[str, Any]]:
153
173
  """执行单步,支持流式输出和取消。
154
174
 
155
- Args:
156
- user_prompt: 用户输入(首步必需,后续可选)
157
- is_first: 是否是首步
175
+ 注意:不再需要 user_prompt 参数,因为:
176
+ - 首次用户输入已在 stream() 的初始化阶段添加
177
+ - 此方法只负责执行步骤:获取屏幕 → 调用 LLM → 执行动作
158
178
 
159
179
  Yields:
160
180
  dict[str, Any]: 事件字典
161
181
  """
162
182
  self._step_count += 1
163
183
 
164
- # 1. 截图和获取当前应用(使用线程池)
184
+ # 1. 获取当前屏幕状态(使用线程池)
165
185
  try:
166
186
  screenshot = await asyncio.to_thread(self.device.get_screenshot)
167
187
  current_app = await asyncio.to_thread(self.device.get_current_app)
@@ -184,42 +204,21 @@ class AsyncGLMAgent:
184
204
  }
185
205
  return
186
206
 
187
- # 2. 构建消息
188
- if is_first:
189
- system_prompt = self.agent_config.system_prompt
190
- if system_prompt is None:
191
- system_prompt = get_system_prompt(self.agent_config.lang)
192
-
193
- self._context.append(MessageBuilder.create_system_message(system_prompt))
194
-
195
- screen_info = MessageBuilder.build_screen_info(current_app)
196
- text_content = f"{user_prompt}\n\n{screen_info}"
197
-
198
- self._context.append(
199
- MessageBuilder.create_user_message(
200
- text=text_content, image_base64=screenshot.base64_data
201
- )
202
- )
203
- else:
204
- screen_info = MessageBuilder.build_screen_info(current_app)
205
- if user_prompt:
206
- text_content = f"{user_prompt}\n\n** Screen Info **\n\n{screen_info}"
207
- else:
208
- text_content = f"** Screen Info **\n\n{screen_info}"
207
+ # 2. 构建消息(统一格式:只有屏幕信息)
208
+ screen_info = MessageBuilder.build_screen_info(current_app)
209
+ text_content = f"** Screen Info **\n\n{screen_info}"
209
210
 
210
- self._context.append(
211
- MessageBuilder.create_user_message(
212
- text=text_content, image_base64=screenshot.base64_data
213
- )
211
+ self._context.append(
212
+ MessageBuilder.create_user_message(
213
+ text=text_content, image_base64=screenshot.base64_data
214
214
  )
215
+ )
215
216
 
216
217
  # 3. 流式调用 OpenAI(真正的异步,可取消)
217
218
  try:
218
219
  if self.agent_config.verbose:
219
220
  msgs = get_messages(self.agent_config.lang)
220
- print("\n" + "=" * 50)
221
- print(f"💭 {msgs['thinking']}:")
222
- print("-" * 50)
221
+ logger.debug(f"💭 {msgs['thinking']}:")
223
222
 
224
223
  thinking_parts = []
225
224
  raw_content = ""
@@ -240,7 +239,7 @@ class AsyncGLMAgent:
240
239
 
241
240
  # Verbose output
242
241
  if self.agent_config.verbose:
243
- print(chunk_data["content"], end="", flush=True)
242
+ logger.debug(chunk_data["content"])
244
243
 
245
244
  elif chunk_data["type"] == "raw":
246
245
  raw_content += chunk_data["content"]
@@ -254,7 +253,7 @@ class AsyncGLMAgent:
254
253
  except Exception as e:
255
254
  logger.error(f"LLM error: {e}")
256
255
  if self.agent_config.verbose:
257
- traceback.print_exc()
256
+ logger.debug(traceback.format_exc())
258
257
 
259
258
  yield {
260
259
  "type": "error",
@@ -285,11 +284,8 @@ class AsyncGLMAgent:
285
284
 
286
285
  if self.agent_config.verbose:
287
286
  msgs = get_messages(self.agent_config.lang)
288
- print()
289
- print("-" * 50)
290
- print(f"🎯 {msgs['action']}:")
291
- print(json.dumps(action, ensure_ascii=False, indent=2))
292
- print("=" * 50 + "\n")
287
+ logger.debug(f"🎯 {msgs['action']}:")
288
+ logger.debug(json.dumps(action, ensure_ascii=False, indent=2))
293
289
 
294
290
  # 5. 执行 action(使用线程池)
295
291
  try:
@@ -299,7 +295,7 @@ class AsyncGLMAgent:
299
295
  except Exception as e:
300
296
  logger.error(f"Action execution error: {e}")
301
297
  if self.agent_config.verbose:
302
- traceback.print_exc()
298
+ logger.debug(traceback.format_exc())
303
299
  result = ActionResult(success=False, should_finish=True, message=str(e))
304
300
 
305
301
  # 6. 更新上下文
@@ -316,11 +312,9 @@ class AsyncGLMAgent:
316
312
 
317
313
  if finished and self.agent_config.verbose:
318
314
  msgs = get_messages(self.agent_config.lang)
319
- print("\n" + "🎉 " + "=" * 48)
320
- print(
315
+ logger.debug(
321
316
  f"✅ {msgs['task_completed']}: {result.message or action.get('message', msgs['done'])}"
322
317
  )
323
- print("=" * 50 + "\n")
324
318
 
325
319
  # 8. 返回步骤结果
326
320
  yield {
@@ -452,8 +446,8 @@ class AsyncGLMAgent:
452
446
  logger.info("AsyncGLMAgent cancelled by user")
453
447
 
454
448
  def reset(self) -> None:
455
- """重置状态。"""
456
- self._context = []
449
+ """重置状态(恢复到初始状态,保留 system message)。"""
450
+ self._context = [self._initial_system_message]
457
451
  self._step_count = 0
458
452
  self._is_running = False
459
453
  self._cancel_event.clear()
@@ -473,35 +467,6 @@ class AsyncGLMAgent:
473
467
  final_message = event["data"].get("message", "")
474
468
  return final_message
475
469
 
476
- async def step(self, task: str | None = None) -> StepResult:
477
- """执行单步(兼容接口)。
478
-
479
- Args:
480
- task: 任务描述(首步必需,后续可选)
481
-
482
- Returns:
483
- StepResult: 步骤结果
484
- """
485
- is_first = len(self._context) == 0
486
- if is_first and not task:
487
- raise ValueError("Task is required for the first step")
488
-
489
- result = None
490
- async for event in self._execute_step_async(task, is_first):
491
- if event["type"] == "step":
492
- result = StepResult(
493
- thinking=event["data"]["thinking"],
494
- action=event["data"]["action"],
495
- success=event["data"]["success"],
496
- finished=event["data"]["finished"],
497
- message=event["data"].get("message"),
498
- )
499
-
500
- if result is None:
501
- raise RuntimeError("Step execution did not produce a result")
502
-
503
- return result
504
-
505
470
  @property
506
471
  def step_count(self) -> int:
507
472
  return self._step_count
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import inspect
4
- from typing import Any, AsyncIterator, Protocol
4
+ from typing import Any, Protocol
5
5
 
6
6
  from AutoGLM_GUI.config import AgentConfig, ModelConfig, StepResult
7
7
 
@@ -76,19 +76,8 @@ class AsyncAgent(Protocol):
76
76
  """
77
77
  ...
78
78
 
79
- async def step(self, task: str | None = None) -> StepResult:
80
- """执行单步,返回步骤结果。
81
-
82
- Args:
83
- task: 任务描述(首步必需,后续可选)
84
-
85
- Returns:
86
- StepResult: 步骤结果
87
- """
88
- ...
89
-
90
- async def stream(self, task: str) -> AsyncIterator[dict[str, Any]]:
91
- """流式执行任务,yield 事件字典。
79
+ def stream(self, task: str) -> Any:
80
+ """流式执行任务,返回异步生成器。
92
81
 
93
82
  这是核心方法,支持:
94
83
  - 实时流式输出 (thinking chunks)
@@ -79,6 +79,22 @@ def _get_static_dir() -> Path | None:
79
79
  def create_app() -> FastAPI:
80
80
  """Build the FastAPI app with routers and static assets."""
81
81
 
82
+ # Configure logging from environment variables (for reload mode)
83
+ # In reload mode, the subprocess imports this module directly, bypassing __main__.py
84
+ # So we need to read log config from environment variables set by the parent process
85
+ import os
86
+
87
+ log_level = os.getenv("AUTOGLM_LOG_LEVEL", "INFO")
88
+ log_file = (
89
+ None
90
+ if os.getenv("AUTOGLM_NO_LOG_FILE")
91
+ else os.getenv("AUTOGLM_LOG_FILE", "logs/autoglm_{time:YYYY-MM-DD}.log")
92
+ )
93
+
94
+ from AutoGLM_GUI.logger import configure_logger
95
+
96
+ configure_logger(console_level=log_level, log_file=log_file)
97
+
82
98
  # Create MCP ASGI app
83
99
  mcp_app = mcp.get_mcp_asgi_app()
84
100
 
@@ -182,7 +182,6 @@ async def chat(request: ChatRequest) -> ChatResponse:
182
182
  result = await agent.run(request.message) # type: ignore[misc]
183
183
 
184
184
  steps = agent.step_count
185
- agent.reset()
186
185
  return ChatResponse(result=result, steps=steps, success=True) # type: ignore[arg-type]
187
186
 
188
187
  except AgentInitializationError as e:
@@ -79,7 +79,8 @@ def configure_logger(
79
79
  _configured = True
80
80
 
81
81
 
82
- # Default initialization (can be reconfigured later)
83
- configure_logger()
82
+ # Note: Logger is NOT auto-initialized to allow early configuration
83
+ # The first call to configure_logger() will initialize the logger
84
+ # If not configured before use, it will use loguru's default behavior (no handlers)
84
85
 
85
86
  __all__ = ["logger", "configure_logger"]
@@ -1 +1 @@
1
- import{j as o}from"./index-BzP-Te33.js";function t(){return o.jsx("div",{className:"p-2",children:o.jsx("h3",{children:"About"})})}export{t as component};
1
+ import{j as o}from"./index-CH4jPveL.js";function t(){return o.jsx("div",{className:"p-2",children:o.jsx("h3",{children:"About"})})}export{t as component};
@@ -1 +1 @@
1
- import{o as u,r as o,j as a,b as r,B as d}from"./index-BzP-Te33.js";import{P as g,c as x,b as f,d as m}from"./popover-BHbCs5Wl.js";import{D as p,d as h,e as w,f as j,g as D}from"./dialog-Cuw3N8_F.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};
1
+ import{o as u,r as o,j as a,b as r,B as d}from"./index-CH4jPveL.js";import{P as g,c as x,b as f,d as m}from"./popover-BnpBfSOh.js";import{D as p,d as h,e as w,f as j,g as D}from"./dialog-IM0Ds7Lf.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};