myagent-ai 1.31.0 → 1.31.1
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.
- package/aiskills/browser_stealth.py +50 -11
- package/main.py +35 -6
- package/package.json +1 -1
|
@@ -165,7 +165,8 @@ class StealthBrowser:
|
|
|
165
165
|
logger.debug(f"反检测 JS 注入提示: {e}")
|
|
166
166
|
|
|
167
167
|
# 等待浏览器完全就绪
|
|
168
|
-
time.sleep
|
|
168
|
+
# Bug Fix: 使用 asyncio.sleep 而非 time.sleep,避免阻塞事件循环
|
|
169
|
+
await asyncio.sleep(1)
|
|
169
170
|
|
|
170
171
|
self._started = True
|
|
171
172
|
logger.info(
|
|
@@ -576,17 +577,45 @@ class StealthBrowser:
|
|
|
576
577
|
if found:
|
|
577
578
|
return found
|
|
578
579
|
|
|
579
|
-
# 3.
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
"/usr/bin/chromium-browser", "/usr/bin/chromium",
|
|
583
|
-
"/snap/bin/chromium",
|
|
584
|
-
):
|
|
585
|
-
if os.path.isfile(p) and os.access(p, os.X_OK):
|
|
586
|
-
return p
|
|
587
|
-
|
|
588
|
-
# 4. Puppeteer 缓存
|
|
580
|
+
# 3. 操作系统特定路径
|
|
581
|
+
import platform
|
|
582
|
+
system = platform.system()
|
|
589
583
|
home = os.path.expanduser("~")
|
|
584
|
+
|
|
585
|
+
if system == "Darwin":
|
|
586
|
+
# macOS 常见路径
|
|
587
|
+
for p in (
|
|
588
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
589
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
590
|
+
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
|
591
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
592
|
+
):
|
|
593
|
+
if os.path.isfile(p) and os.access(p, os.X_OK):
|
|
594
|
+
return p
|
|
595
|
+
elif system == "Windows":
|
|
596
|
+
# Windows 常见路径
|
|
597
|
+
for p in (
|
|
598
|
+
os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), "Google", "Chrome", "Application", "chrome.exe"),
|
|
599
|
+
os.path.join(os.environ.get("PROGRAMFILES(X86)", "C:\\Program Files (x86)"), "Google", "Chrome", "Application", "chrome.exe"),
|
|
600
|
+
os.path.join(os.environ.get("LOCALAPPDATA", ""), "Google", "Chrome", "Application", "chrome.exe"),
|
|
601
|
+
os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), "Microsoft", "Edge", "Application", "msedge.exe"),
|
|
602
|
+
os.path.join(os.environ.get("LOCALAPPDATA", ""), "BraveSoftware", "Brave-Browser", "Application", "brave.exe"),
|
|
603
|
+
):
|
|
604
|
+
if os.path.isfile(p):
|
|
605
|
+
return p
|
|
606
|
+
else:
|
|
607
|
+
# Linux 常见路径
|
|
608
|
+
for p in (
|
|
609
|
+
"/usr/bin/google-chrome", "/usr/bin/google-chrome-stable",
|
|
610
|
+
"/usr/bin/chromium-browser", "/usr/bin/chromium",
|
|
611
|
+
"/snap/bin/chromium",
|
|
612
|
+
"/usr/bin/brave-browser",
|
|
613
|
+
"/usr/bin/microsoft-edge",
|
|
614
|
+
):
|
|
615
|
+
if os.path.isfile(p) and os.access(p, os.X_OK):
|
|
616
|
+
return p
|
|
617
|
+
|
|
618
|
+
# 4. Puppeteer / Playwright 缓存
|
|
590
619
|
for cache in (
|
|
591
620
|
os.path.join(home, ".cache", "puppeteer", "chrome"),
|
|
592
621
|
os.path.join(home, ".cache", "ms-playwright"),
|
|
@@ -621,8 +650,18 @@ def get_stealth_browser(
|
|
|
621
650
|
with _browser_lock:
|
|
622
651
|
if profile_name in _browsers:
|
|
623
652
|
browser = _browsers[profile_name]
|
|
653
|
+
# Bug Fix: 检测浏览器是否已崩溃,如果崩溃则清理并重建
|
|
624
654
|
if browser._started and browser._ensure_page():
|
|
625
655
|
return browser
|
|
656
|
+
else:
|
|
657
|
+
# 浏览器已崩溃或未启动,清理旧实例
|
|
658
|
+
logger.info(f"浏览器实例失效 (profile={profile_name}),正在重建...")
|
|
659
|
+
try:
|
|
660
|
+
if browser._browser:
|
|
661
|
+
browser._browser.quit()
|
|
662
|
+
except Exception:
|
|
663
|
+
pass
|
|
664
|
+
del _browsers[profile_name]
|
|
626
665
|
|
|
627
666
|
browser = StealthBrowser(profile_name=profile_name, headless=headless)
|
|
628
667
|
_browsers[profile_name] = browser
|
package/main.py
CHANGED
|
@@ -68,9 +68,11 @@ def _get_screen_resolution() -> tuple[int, int]:
|
|
|
68
68
|
if "dimensions:" in line:
|
|
69
69
|
parts = line.split()
|
|
70
70
|
for p in parts:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
# Bug Fix: 使用更严格的正则匹配分辨率格式 (数字x数字)
|
|
72
|
+
import re as _re
|
|
73
|
+
m = _re.match(r"^(\d+)x(\d+)$", p)
|
|
74
|
+
if m:
|
|
75
|
+
return int(m.group(1)), int(m.group(2))
|
|
74
76
|
except Exception:
|
|
75
77
|
pass
|
|
76
78
|
return 1920, 1080
|
|
@@ -145,6 +147,9 @@ class MyAgentApp:
|
|
|
145
147
|
# 权限管理器
|
|
146
148
|
self.permission_manager: PermissionManager | None = None
|
|
147
149
|
|
|
150
|
+
# Bug Fix: _running_service 必须在 __init__ 初始化,否则托盘菜单访问时 AttributeError
|
|
151
|
+
self._running_service = False
|
|
152
|
+
|
|
148
153
|
# 交互式会话
|
|
149
154
|
self._session_id = "cli_default"
|
|
150
155
|
|
|
@@ -583,11 +588,15 @@ class MyAgentApp:
|
|
|
583
588
|
|
|
584
589
|
# 处理消息
|
|
585
590
|
# [v1.20.13] 使用会话级锁防止并发处理同一会话
|
|
591
|
+
# Bug Fix: 使用 try_acquire 模式避免 locked() + acquire 的 TOCTOU 竞争
|
|
586
592
|
session_lock = await self._get_session_lock(session_id)
|
|
587
|
-
if session_lock.
|
|
593
|
+
if not session_lock.acquire(blocking=False):
|
|
588
594
|
return # 同一会话正在处理中,跳过(聊天平台消息有去重机制)
|
|
589
|
-
|
|
595
|
+
try:
|
|
590
596
|
response_text = await self.process_message(message.text, session_id)
|
|
597
|
+
finally:
|
|
598
|
+
session_lock.release()
|
|
599
|
+
self._cleanup_session_locks()
|
|
591
600
|
|
|
592
601
|
# [v1.20.8] 将回复中的相对路径文件链接替换为绝对 URL
|
|
593
602
|
# (file_send 生成的 /api/file/xxx 链接在 Telegram/Discord 等外部平台无法访问)
|
|
@@ -799,7 +808,8 @@ class MyAgentApp:
|
|
|
799
808
|
for perm in config.get("all_permissions", []):
|
|
800
809
|
label = labels.get(perm, perm)
|
|
801
810
|
status = "✅ 开启" if defaults.get(perm, False) else "❌ 关闭"
|
|
802
|
-
|
|
811
|
+
# Bug Fix: 使用 ASCII 空格而非 Unicode Ideographic Space (U+3000) 进行填充
|
|
812
|
+
print(f" {label:<8} ({perm}): {status}")
|
|
803
813
|
print()
|
|
804
814
|
|
|
805
815
|
# Per-agent 覆盖
|
|
@@ -828,11 +838,27 @@ class MyAgentApp:
|
|
|
828
838
|
print(" (提示: 使用 'session <名称>' 切换会话)")
|
|
829
839
|
print()
|
|
830
840
|
|
|
841
|
+
def _cleanup_session_locks(self):
|
|
842
|
+
"""清理过期的会话锁,防止内存泄漏。保留最近 100 个会话锁。"""
|
|
843
|
+
if len(self._session_locks) > 100:
|
|
844
|
+
# 按 FIFO 顺序移除最旧的锁
|
|
845
|
+
keys = list(self._session_locks.keys())
|
|
846
|
+
for k in keys[:len(keys) - 100]:
|
|
847
|
+
del self._session_locks[k]
|
|
848
|
+
|
|
831
849
|
async def shutdown(self):
|
|
832
850
|
"""关闭所有组件"""
|
|
833
851
|
self.logger.info("MyAgent 正在关闭...")
|
|
834
852
|
self._running = False
|
|
835
853
|
|
|
854
|
+
# Bug Fix: 关闭所有反检测浏览器实例,避免 Chrome 进程残留
|
|
855
|
+
try:
|
|
856
|
+
from aiskills.browser_stealth import close_stealth_browser
|
|
857
|
+
close_stealth_browser(profile_name="")
|
|
858
|
+
self.logger.info("已关闭所有反检测浏览器实例")
|
|
859
|
+
except Exception as e:
|
|
860
|
+
self.logger.debug(f"关闭反检测浏览器时出错: {e}")
|
|
861
|
+
|
|
836
862
|
if self.communication_manager:
|
|
837
863
|
await self.communication_manager.stop()
|
|
838
864
|
|
|
@@ -848,6 +874,9 @@ class MyAgentApp:
|
|
|
848
874
|
if self.memory:
|
|
849
875
|
self.memory.close()
|
|
850
876
|
|
|
877
|
+
# 清理会话锁
|
|
878
|
+
self._session_locks.clear()
|
|
879
|
+
|
|
851
880
|
self.logger.info("MyAgent 已关闭")
|
|
852
881
|
|
|
853
882
|
|