myagent-ai 1.25.7 → 1.25.9

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 (37) hide show
  1. package/core/version.py +36 -10
  2. package/myagent/core/version.py +36 -10
  3. package/myagent/main.py +4 -3
  4. package/myagent/package.json +1 -1
  5. package/myagent/start.sh +0 -0
  6. package/myagent/web/__init__.py +0 -0
  7. package/myagent/web/api_server.py +0 -227
  8. package/myagent/web/tts_handler.py +0 -0
  9. package/myagent/web/ui/admin/admin-agentchat.js +0 -0
  10. package/myagent/web/ui/admin/admin-agents.js +0 -0
  11. package/myagent/web/ui/admin/admin-core.js +0 -0
  12. package/myagent/web/ui/admin/admin-dashboard.js +0 -0
  13. package/myagent/web/ui/admin/admin-executor.js +0 -0
  14. package/myagent/web/ui/admin/admin-files.js +0 -0
  15. package/myagent/web/ui/admin/admin-llm.js +0 -0
  16. package/myagent/web/ui/admin/admin-logs.js +0 -0
  17. package/myagent/web/ui/admin/admin-memory.js +0 -0
  18. package/myagent/web/ui/admin/admin-org.js +0 -0
  19. package/myagent/web/ui/admin/admin-permissions.js +0 -0
  20. package/myagent/web/ui/admin/admin-platforms.js +0 -0
  21. package/myagent/web/ui/admin/admin-sessions.js +0 -0
  22. package/myagent/web/ui/admin/admin-skills.js +0 -0
  23. package/myagent/web/ui/admin/admin-system.js +0 -0
  24. package/myagent/web/ui/admin/admin-tasks.js +0 -0
  25. package/myagent/web/ui/chat/chat.css +0 -0
  26. package/myagent/web/ui/chat/chat.js +0 -0
  27. package/myagent/web/ui/chat/chat_container.html +0 -0
  28. package/myagent/web/ui/chat/chat_main.js +15 -224
  29. package/myagent/web/ui/chat/flow_engine.js +0 -0
  30. package/myagent/web/ui/chat/groupchat.js +0 -0
  31. package/myagent/web/ui/chat/left_sessions.html +0 -0
  32. package/myagent/web/ui/chat/middle_chat.html +0 -0
  33. package/myagent/web/ui/chat/right_agents.html +0 -0
  34. package/myagent/web/ui/index.html +0 -0
  35. package/myagent/worklog-v1.22.md +12 -0
  36. package/myagent/worklog.md +44 -0
  37. package/package.json +1 -1
package/core/version.py CHANGED
@@ -14,17 +14,43 @@ from pathlib import Path
14
14
 
15
15
 
16
16
  def _version_from_package_json() -> str:
17
- """从 package.json 读取版本号(单一数据源)"""
17
+ """从 package.json 读取版本号(单一数据源)
18
+
19
+ npm 全局安装时,包结构为:
20
+ /usr/lib/node_modules/myagent-ai/ ← 根 package.json (npm bin 入口)
21
+ /usr/lib/node_modules/myagent-ai/myagent/ ← 子目录 package.json (代码)
22
+
23
+ Python 代码运行时 sys.path 包含 myagent/ 子目录,
24
+ Path(__file__).parent.parent 找到的是 myagent/package.json。
25
+ 但根 package.json 才是 npm 管理的版本号(single source of truth)。
26
+
27
+ 策略: 同时查找两层 package.json,优先取有更高版本号的。
28
+ """
29
+ candidates = [
30
+ Path(__file__).parent.parent / "package.json", # myagent/package.json
31
+ Path(__file__).parent.parent.parent / "package.json", # 根 package.json
32
+ ]
33
+ best = ""
34
+ for pkg_path in candidates:
35
+ try:
36
+ if pkg_path.exists():
37
+ data = json.loads(pkg_path.read_text(encoding="utf-8"))
38
+ ver = data.get("version", "")
39
+ if ver:
40
+ # 取较高的版本号
41
+ if not best or _ver_tuple(ver) > _ver_tuple(best):
42
+ best = ver
43
+ except Exception:
44
+ pass
45
+ return best
46
+
47
+
48
+ def _ver_tuple(v: str) -> tuple:
49
+ """将版本字符串转为可比较的 tuple,如 '1.25.7' → (1, 25, 7)"""
18
50
  try:
19
- pkg_path = Path(__file__).parent.parent / "package.json"
20
- if pkg_path.exists():
21
- data = json.loads(pkg_path.read_text(encoding="utf-8"))
22
- ver = data.get("version", "")
23
- if ver:
24
- return ver
25
- except Exception:
26
- pass
27
- return ""
51
+ return tuple(int(x) for x in v.split(".")[:3])
52
+ except (ValueError, AttributeError):
53
+ return (0, 0, 0)
28
54
 
29
55
 
30
56
  def _version_from_git() -> str:
@@ -14,17 +14,43 @@ from pathlib import Path
14
14
 
15
15
 
16
16
  def _version_from_package_json() -> str:
17
- """从 package.json 读取版本号(单一数据源)"""
17
+ """从 package.json 读取版本号(单一数据源)
18
+
19
+ npm 全局安装时,包结构为:
20
+ /usr/lib/node_modules/myagent-ai/ ← 根 package.json (npm bin 入口)
21
+ /usr/lib/node_modules/myagent-ai/myagent/ ← 子目录 package.json (代码)
22
+
23
+ Python 代码运行时 sys.path 包含 myagent/ 子目录,
24
+ Path(__file__).parent.parent 找到的是 myagent/package.json。
25
+ 但根 package.json 才是 npm 管理的版本号(single source of truth)。
26
+
27
+ 策略: 同时查找两层 package.json,优先取有更高版本号的。
28
+ """
29
+ candidates = [
30
+ Path(__file__).parent.parent / "package.json", # myagent/package.json
31
+ Path(__file__).parent.parent.parent / "package.json", # 根 package.json
32
+ ]
33
+ best = ""
34
+ for pkg_path in candidates:
35
+ try:
36
+ if pkg_path.exists():
37
+ data = json.loads(pkg_path.read_text(encoding="utf-8"))
38
+ ver = data.get("version", "")
39
+ if ver:
40
+ # 取较高的版本号
41
+ if not best or _ver_tuple(ver) > _ver_tuple(best):
42
+ best = ver
43
+ except Exception:
44
+ pass
45
+ return best
46
+
47
+
48
+ def _ver_tuple(v: str) -> tuple:
49
+ """将版本字符串转为可比较的 tuple,如 '1.25.7' → (1, 25, 7)"""
18
50
  try:
19
- pkg_path = Path(__file__).parent.parent / "package.json"
20
- if pkg_path.exists():
21
- data = json.loads(pkg_path.read_text(encoding="utf-8"))
22
- ver = data.get("version", "")
23
- if ver:
24
- return ver
25
- except Exception:
26
- pass
27
- return ""
51
+ return tuple(int(x) for x in v.split(".")[:3])
52
+ except (ValueError, AttributeError):
53
+ return (0, 0, 0)
28
54
 
29
55
 
30
56
  def _version_from_git() -> str:
package/myagent/main.py CHANGED
@@ -17,10 +17,11 @@ import signal
17
17
  import threading
18
18
  from pathlib import Path
19
19
 
20
- # 确保项目根目录在 Python 路径中
20
+ # 确保项目根目录在 Python 路径中(实际代码在 myagent/ 子目录)
21
21
  PROJECT_ROOT = Path(__file__).parent.resolve()
22
- if str(PROJECT_ROOT) not in sys.path:
23
- sys.path.insert(0, str(PROJECT_ROOT))
22
+ MYAGENT_DIR = PROJECT_ROOT / 'myagent'
23
+ if str(MYAGENT_DIR) not in sys.path:
24
+ sys.path.insert(0, str(MYAGENT_DIR))
24
25
 
25
26
  from config import get_config, ConfigManager
26
27
  from core.logger import setup_logger, get_logger
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.25.6",
3
+ "version": "1.25.9",
4
4
  "description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
5
5
  "main": "main.py",
6
6
  "bin": {
package/myagent/start.sh CHANGED
File without changes
File without changes
@@ -595,8 +595,6 @@ class ApiServer:
595
595
  r.add_get("/api/web_control/proxy", self.handle_wc_proxy)
596
596
  r.add_post("/api/web_control/proxy", self.handle_wc_proxy_post)
597
597
  r.add_get("/api/web_control/panel", self.handle_wc_panel)
598
- # [v1.25.3] 人机交互 API
599
- r.add_post("/api/web_control/human_done", self.handle_wc_human_done)
600
598
  ui_dir = Path(__file__).parent / "ui"
601
599
  if ui_dir.exists():
602
600
  r.add_static("/ui", str(ui_dir), append_version=True)
@@ -1437,45 +1435,6 @@ function tryDirectConnect() {{
1437
1435
  ok = await self._get_wc_manager().submit_result(sid, cmd_id, result)
1438
1436
  return web.json_response({"success": ok})
1439
1437
 
1440
- async def handle_wc_human_done(self, request):
1441
- """[v1.25.3] POST /api/web_control/human_done - 用户完成人机交互, 唤醒等待的 Agent"""
1442
- try:
1443
- data = await request.json()
1444
- except:
1445
- return web.json_response({"success": False, "error": "Invalid JSON"}, status=400)
1446
- sid = data.get('session_id', '')
1447
- if not sid:
1448
- return web.json_response({"success": False, "error": "Missing session_id"}, status=400)
1449
- mgr = self._get_wc_manager()
1450
- session = mgr.get_session(sid)
1451
- if not session:
1452
- return web.json_response({"success": False, "error": "Session not found"}, status=404)
1453
- # 存储用户的结果(备注等)
1454
- session.human_result = {
1455
- "note": data.get("note", ""),
1456
- "current_url": data.get("current_url", ""),
1457
- "timestamp": time.time(),
1458
- }
1459
- # 捕获 iframe 报告的 cookies
1460
- iframe_cookies = data.get("cookies", "")
1461
- if iframe_cookies:
1462
- parsed_url = urlparse(session.current_url)
1463
- hostname = parsed_url.hostname or ""
1464
- for part in iframe_cookies.split(';'):
1465
- part = part.strip()
1466
- if '=' in part:
1467
- name, _, value = part.partition('=')
1468
- name = name.strip()
1469
- value = value.strip()
1470
- if name and value:
1471
- session.cookies[f"{hostname}::{name}"] = value
1472
- # 唤醒等待的 Agent
1473
- if session.human_event and not session.human_event.is_set():
1474
- session.human_event.set()
1475
- logger.info(f"[WebControl] 人机交互完成 (session: {sid})")
1476
- return web.json_response({"success": True})
1477
- return web.json_response({"success": False, "error": "No pending human_interact"})
1478
-
1479
1438
  async def handle_wc_proxy(self, request):
1480
1439
  """GET /api/web_control/proxy?url=xxx&sid=xxx - 代理网页请求"""
1481
1440
  url = request.query.get('url', '')
@@ -1670,17 +1629,6 @@ body {{ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans
1670
1629
  .wc-modal h3 {{ margin-bottom:10px; font-size:14px; }}
1671
1630
  .wc-modal textarea {{ width:100%; min-height:120px; padding:8px; border-radius:4px; border:1px solid {input_border}; background:{input_bg}; color:{text_color}; font-size:12px; font-family:monospace; resize:vertical; }}
1672
1631
  .wc-modal-actions {{ display:flex; gap:8px; margin-top:10px; justify-content:flex-end; }}
1673
- /* [v1.25.4] 人机交互模式 (增强版) */
1674
- .wc-human-bar {{ display:none; align-items:center; gap:8px; padding:6px 12px; background:linear-gradient(135deg,#667eea 0%,#764ba2 100%); color:#fff; font-size:12px; font-weight:600; flex-shrink:0; }}
1675
- .wc-human-bar.show {{ display:flex; }}
1676
- .wc-human-bar .wc-human-prompt {{ flex:1; }}
1677
- .wc-human-timer {{ font-size:13px; font-weight:700; min-width:40px; text-align:right; }}
1678
- .wc-btn-human-done {{ background:#00c853; color:#fff; padding:4px 14px; border-radius:4px; border:none; cursor:pointer; font-size:12px; font-weight:700; white-space:nowrap; animation:pulse-btn 1.5s infinite; }}
1679
- .wc-btn-human-done:hover {{ background:#00e676; }}
1680
- .wc-btn-human-cancel {{ background:rgba(255,255,255,0.2); color:#fff; padding:4px 10px; border-radius:4px; border:1px solid rgba(255,255,255,0.4); cursor:pointer; font-size:11px; }}
1681
- .wc-btn-human-refresh {{ background:rgba(255,255,255,0.15); color:#fff; padding:4px 10px; border-radius:4px; border:1px solid rgba(255,255,255,0.3); cursor:pointer; font-size:11px; white-space:nowrap; }}
1682
- .wc-btn-human-refresh:hover {{ background:rgba(255,255,255,0.3); }}
1683
- @keyframes pulse-btn {{ 0%,100% {{ box-shadow:0 0 0 0 rgba(0,200,83,0.4); }} 50% {{ box-shadow:0 0 0 6px rgba(0,200,83,0); }} }}
1684
1632
  </style>
1685
1633
  </head>
1686
1634
  <body>
@@ -1713,27 +1661,6 @@ body {{ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans
1713
1661
  <span id="wcPageInfo" class="wc-toolbar-info"></span>
1714
1662
  </div>
1715
1663
 
1716
- <!-- [v1.25.4] 人机交互横栏 (增强版: 倒计时 + 备注 + 刷新QR码) -->
1717
- <div class="wc-human-bar" id="wcHumanBar">
1718
- <span id="wcHumanPrompt" class="wc-human-prompt">&#x1F3AF; 请在上方页面完成登录或验证操作...</span>
1719
- <span id="wcHumanTimer" class="wc-human-timer" style="color:#ffd54f;margin-right:4px;font-variant-numeric:tabular-nums;"></span>
1720
- <button class="wc-btn-human-refresh" onclick="wcHumanRefresh()" title="刷新页面(重新获取二维码)">&#x1F504; 刷新</button>
1721
- <button class="wc-btn-human-cancel" onclick="wcHumanCancel()">&#x274C; 取消</button>
1722
- <button class="wc-btn-human-done" onclick="wcHumanDone()">&#x2705; 完成登录</button>
1723
- </div>
1724
-
1725
- <!-- [v1.25.4] 人机交互备注弹窗 -->
1726
- <div class="wc-overlay" id="wcNoteOverlay">
1727
- <div class="wc-modal">
1728
- <h3>&#x1F4DD; 操作备注 (可选)</h3>
1729
- <textarea id="wcNoteInput" placeholder="记录你做了什么(如:已扫码登录、输入了用户名密码等)..."></textarea>
1730
- <div class="wc-modal-actions">
1731
- <button class="wc-btn" onclick="wcCloseNote()">跳过</button>
1732
- <button class="wc-btn wc-btn-primary" onclick="wcSubmitNote()">确认完成</button>
1733
- </div>
1734
- </div>
1735
- </div>
1736
-
1737
1664
  <!-- JS Console Modal -->
1738
1665
  <div class="wc-overlay" id="wcConsoleOverlay">
1739
1666
  <div class="wc-modal">
@@ -1833,20 +1760,6 @@ function wcExecuteCommand(cmd) {{
1833
1760
  wcSubmitResult({{ cmdId: cmd.id, success: true, closed: true }});
1834
1761
  return;
1835
1762
  }}
1836
- // [v1.25.4] 人机交互命令 — 显示人机模式横栏 (增强版: 带倒计时)
1837
- if (cmd.action === 'human_interact') {{
1838
- var prompt = (cmd.params && cmd.params.prompt) ? cmd.params.prompt : '';
1839
- var timeout = (cmd.params && cmd.params.timeout) ? parseInt(cmd.params.timeout) : 300;
1840
- wcShowHumanBar(prompt, timeout);
1841
- wcSubmitResult({{ cmdId: cmd.id, success: true, human_mode: true }});
1842
- return;
1843
- }}
1844
- // [v1.25.3] 恢复 Agent 模式命令
1845
- if (cmd.action === 'agent_mode') {{
1846
- wcHideHumanBar();
1847
- wcSubmitResult({{ cmdId: cmd.id, success: true, human_mode: false }});
1848
- return;
1849
- }}
1850
1763
 
1851
1764
  // 其他命令通过 postMessage 发送到 iframe 中的控制脚本
1852
1765
  try {{
@@ -1911,146 +1824,6 @@ function wcToggleFullscreen() {{
1911
1824
  }}
1912
1825
  }}
1913
1826
 
1914
- // ── [v1.25.4] 人机交互模式 (增强版) ──
1915
- var wcHumanMode = false;
1916
- var wcHumanTimer = null;
1917
- var wcHumanStartTime = 0;
1918
- var wcHumanTimeout = 300; // 默认5分钟
1919
- var wcHumanLoginUrl = ''; // [v1.25.4] 记录登录URL,用于刷新
1920
-
1921
- function wcShowHumanBar(prompt, timeout) {{
1922
- wcHumanMode = true;
1923
- var bar = document.getElementById('wcHumanBar');
1924
- var promptEl = document.getElementById('wcHumanPrompt');
1925
- if (bar) bar.classList.add('show');
1926
- if (promptEl && prompt) promptEl.textContent = '\U0001f3af ' + prompt;
1927
- document.getElementById('wcStatus').textContent = '人机交互模式';
1928
- document.getElementById('wcStatus').className = 'wc-status connected';
1929
- document.getElementById('wcStatus').style.color = '#667eea';
1930
- // 记录当前URL用于刷新
1931
- wcHumanLoginUrl = document.getElementById('wcUrlInput').value || '';
1932
- // 启动倒计时
1933
- wcHumanTimeout = timeout || 300;
1934
- wcHumanStartTime = Date.now();
1935
- if (wcHumanTimer) clearInterval(wcHumanTimer);
1936
- wcHumanTimer = setInterval(wcUpdateTimer, 1000);
1937
- wcUpdateTimer();
1938
- // 通知父窗口进入人机模式
1939
- window.parent.postMessage({{ __webControlPanel: true, action: 'human_interact', session_id: WC_SESSION_ID }}, '*');
1940
- }}
1941
-
1942
- function wcHideHumanBar() {{
1943
- wcHumanMode = false;
1944
- var bar = document.getElementById('wcHumanBar');
1945
- if (bar) bar.classList.remove('show');
1946
- document.getElementById('wcStatus').textContent = '已连接';
1947
- document.getElementById('wcStatus').style.color = '';
1948
- // 停止倒计时
1949
- if (wcHumanTimer) {{ clearInterval(wcHumanTimer); wcHumanTimer = null; }}
1950
- document.getElementById('wcHumanTimer').textContent = '';
1951
- // 通知父窗口退出人机模式
1952
- window.parent.postMessage({{ __webControlPanel: true, action: 'human_done', session_id: WC_SESSION_ID }}, '*');
1953
- }}
1954
-
1955
- // [v1.25.4] 倒计时显示
1956
- function wcUpdateTimer() {{
1957
- var elapsed = Math.floor((Date.now() - wcHumanStartTime) / 1000);
1958
- var remaining = wcHumanTimeout - elapsed;
1959
- if (remaining < 0) remaining = 0;
1960
- var minutes = Math.floor(remaining / 60);
1961
- var seconds = remaining % 60;
1962
- var timerEl = document.getElementById('wcHumanTimer');
1963
- if (timerEl) {{
1964
- timerEl.textContent = String(minutes).padStart(2, '0') + ':' + String(seconds).padStart(2, '0');
1965
- // 最后30秒变红
1966
- timerEl.style.color = remaining <= 30 ? '#ff5252' : '#ffd54f';
1967
- }}
1968
- if (remaining <= 0 && wcHumanTimer) {{
1969
- clearInterval(wcHumanTimer);
1970
- wcHumanTimer = null;
1971
- }}
1972
- }}
1973
-
1974
- // [v1.25.4] 刷新页面 (重新获取QR码)
1975
- function wcHumanRefresh() {{
1976
- var url = wcHumanLoginUrl || document.getElementById('wcUrlInput').value || '';
1977
- if (url) {{
1978
- wcNavigate(url);
1979
- wcShowLoading('刷新页面...');
1980
- }}
1981
- }}
1982
-
1983
- // [v1.25.4] 人机完成 -> 先弹出备注框
1984
- function wcHumanDone() {{
1985
- document.getElementById('wcNoteOverlay').classList.add('show');
1986
- document.getElementById('wcNoteInput').value = '';
1987
- document.getElementById('wcNoteInput').focus();
1988
- }}
1989
- function wcCloseNote() {{
1990
- document.getElementById('wcNoteOverlay').classList.remove('show');
1991
- // 无备注直接完成
1992
- wcDoHumanDone('');
1993
- }}
1994
- function wcSubmitNote() {{
1995
- var note = document.getElementById('wcNoteInput').value.trim();
1996
- document.getElementById('wcNoteOverlay').classList.remove('show');
1997
- wcDoHumanDone(note);
1998
- }}
1999
-
2000
- async function wcDoHumanDone(userNote) {{
2001
- // 从 iframe 捕获 cookies
2002
- var iframeCookies = '';
2003
- try {{
2004
- var iframe = document.getElementById('wcIframe');
2005
- if (iframe && iframe.contentWindow && iframe.contentWindow.document) {{
2006
- iframeCookies = iframe.contentWindow.document.cookie || '';
2007
- }}
2008
- }} catch(e) {{}}
2009
- // 获取当前 URL
2010
- var currentUrl = document.getElementById('wcUrlInput').value || '';
2011
-
2012
- wcHideHumanBar();
2013
-
2014
- // 通知服务端用户已完成
2015
- try {{
2016
- var resp = await fetch('/api/web_control/human_done', {{
2017
- method: 'POST',
2018
- headers: {{ 'Content-Type': 'application/json' }},
2019
- body: JSON.stringify({{
2020
- session_id: WC_SESSION_ID,
2021
- current_url: currentUrl,
2022
- cookies: iframeCookies,
2023
- note: userNote || ''
2024
- }})
2025
- }});
2026
- var result = await resp.json();
2027
- if (result.success) {{
2028
- console.log('[WebControl] 人机交互完成, Agent 已恢复');
2029
- }} else {{
2030
- console.warn('[WebControl] human_done 失败:', result.error);
2031
- }}
2032
- }} catch(e) {{
2033
- console.error('[WebControl] human_done error:', e);
2034
- }}
2035
- }}
2036
-
2037
- async function wcHumanCancel() {{
2038
- wcHideHumanBar();
2039
- // 取消时也通知服务端
2040
- try {{
2041
- await fetch('/api/web_control/human_done', {{
2042
- method: 'POST',
2043
- headers: {{ 'Content-Type': 'application/json' }},
2044
- body: JSON.stringify({{
2045
- session_id: WC_SESSION_ID,
2046
- current_url: document.getElementById('wcUrlInput').value || '',
2047
- cookies: '',
2048
- note: '用户取消'
2049
- }})
2050
- }});
2051
- }} catch(e) {{}}
2052
- }}
2053
-
2054
1827
  // ── 辅助 ──
2055
1828
  function wcShowLoading(text) {{
2056
1829
  var el = document.getElementById('wcLoading');
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1603,26 +1603,6 @@ window.addEventListener('message', function(event) {
1603
1603
  api('/api/web_control/poll?sid=' + wcCurrentSessionId).catch(function(){});
1604
1604
  } else if (action === 'close' || action === 'closed') {
1605
1605
  closeWCOverlay();
1606
- } else if (action === 'human_interact') {
1607
- // [v1.25.3] 面板进入人机模式 - 在聊天中显示提示
1608
- wcCurrentSessionId = event.data.session_id || wcCurrentSessionId;
1609
- var wcPlatform = lastEvent.platform || '';
1610
- var wcPrompt = lastEvent.prompt || '等待你在网页面板中完成操作...';
1611
- appendMessage('system', '🎯 Agent 已暂停,' + wcPrompt + (wcPlatform ? ' (' + wcPlatform + ')' : ''));
1612
- } else if (action === 'human_done') {
1613
- // [v1.25.3] 人机操作完成
1614
- appendMessage('system', '✅ 人机交互完成,Agent 已恢复控制');
1615
- } else if (action === 'login') {
1616
- // [v1.25.4] 登录流程开始
1617
- wcCurrentSessionId = event.data.session_id || wcCurrentSessionId;
1618
- var loginPlatform = lastEvent.platform || '';
1619
- var loginPrompt = lastEvent.prompt || '请在网页面板中完成登录...';
1620
- appendMessage('system', '🔐 ' + loginPrompt + (loginPlatform ? ' [' + loginPlatform + ']' : ''));
1621
- } else if (action === 'login_done') {
1622
- // [v1.25.4] 登录完成
1623
- var loginOk = lastEvent.login_success;
1624
- var loginPlat = lastEvent.platform || '';
1625
- appendMessage('system', (loginOk ? '✅ ' : '⚠️ ') + (loginPlat ? loginPlat + ' ' : '') + '登录操作完成' + (loginOk ? ' (已登录成功)' : ''));
1626
1606
  }
1627
1607
  }
1628
1608
  });
@@ -3419,22 +3399,6 @@ window.buildMessageHtml = function(msg, idx, agent) {
3419
3399
  } else if (wcAction === 'close') {
3420
3400
  wcDesc = '已关闭控制面板';
3421
3401
  wcIcon = '⏹';
3422
- } else if (wcAction === 'human_interact') {
3423
- wcDesc = lastEvent.prompt || '等待用户手动操作...';
3424
- wcTitle = '人机交互模式';
3425
- wcIcon = '🎯';
3426
- } else if (wcAction === 'human_done') {
3427
- wcDesc = lastEvent.timed_out ? '人机交互超时' : '用户已完成操作';
3428
- wcTitle = '人机交互完成';
3429
- wcIcon = '✅';
3430
- } else if (wcAction === 'login') {
3431
- wcDesc = (lastEvent.platform || '登录') + ' — ' + (lastEvent.prompt || '请在网页面板中完成登录');
3432
- wcTitle = '登录 ' + (lastEvent.platform || '');
3433
- wcIcon = '🔐';
3434
- } else if (wcAction === 'login_done') {
3435
- wcDesc = lastEvent.login_success ? '登录成功' : '登录操作完成';
3436
- wcTitle = (lastEvent.platform || '') + ' 登录完成';
3437
- wcIcon = lastEvent.login_success ? '✅' : '⚠️';
3438
3402
  }
3439
3403
  return '<div class="msg-wc-card" onclick="if(typeof openWCOverlay===\'function\')openWCOverlay(\'' + escapeHtml(wcSessionId) + '\',\'' + escapeHtml(wcUrl) + '\')" title="点击重新打开">' +
3440
3404
  '<span class="msg-wc-icon">' + wcIcon + '</span>' +
@@ -4740,8 +4704,7 @@ document.addEventListener('keydown', (e) => {
4740
4704
  // ══════════════════════════════════════════════════════
4741
4705
  // ── Setup Wizard ──
4742
4706
  // ══════════════════════════════════════════════════════
4743
- let setupStep = 0; // 0: welcome, 1: provider, 2: config, 3: platforms, 4: done
4744
- let setupPlatforms = {}; // { platform: { enabled, token, ... } }
4707
+ let setupStep = 0; // 0: welcome, 1: provider, 2: config, 3: done
4745
4708
  let setupProvider = 'modelscope';
4746
4709
 
4747
4710
  const SETUP_PROVIDERS = {
@@ -4858,7 +4821,7 @@ function skipSetup() {
4858
4821
 
4859
4822
  function renderSetupDots() {
4860
4823
  let html = '<div class="setup-steps">';
4861
- for (let i = 0; i < 5; i++) {
4824
+ for (let i = 0; i < 4; i++) {
4862
4825
  let cls = 'setup-step-dot';
4863
4826
  if (i < setupStep) cls += ' done';
4864
4827
  else if (i === setupStep) cls += ' active';
@@ -4975,65 +4938,19 @@ function renderSetupStep() {
4975
4938
  <div class="setup-status" id="setupStatus"></div>
4976
4939
  <div class="setup-actions">
4977
4940
  <button class="setup-btn setup-btn-secondary" onclick="setupStep=1;renderSetupStep()">← 上一步</button>
4978
- <button class="setup-btn setup-btn-skip" onclick="setupStep=4;renderSetupStep()">跳过,稍后配置</button>
4941
+ <button class="setup-btn setup-btn-skip" onclick="setupStep=3;renderSetupStep()">跳过,稍后配置</button>
4979
4942
  <button class="setup-btn setup-btn-secondary" onclick="setupTestConnection()">🔗 测试连接</button>
4980
- <button class="setup-btn setup-btn-primary" onclick="setupSaveLLMAndNext()">下一步 →</button>
4943
+ <button class="setup-btn setup-btn-primary" onclick="setupSaveAndComplete()">✅ 保存并完成</button>
4981
4944
  </div>`;
4982
4945
  } else if (setupStep === 3) {
4983
- // Platform integration
4984
- const platformList = [
4985
- { key: 'telegram', icon: '📱', name: 'Telegram', desc: '通过 Bot Token 接入', tokenLabel: 'Bot Token', hasAppId: false },
4986
- { key: 'discord', icon: '🎮', name: 'Discord', desc: '通过 Bot Token 接入', tokenLabel: 'Bot Token', hasAppId: false },
4987
- { key: 'feishu', icon: '🐦', name: '飞书', desc: '通过 App ID + App Secret 接入', tokenLabel: 'App Secret', hasAppId: true },
4988
- { key: 'qq', icon: '🐧', name: 'QQ', desc: '通过 Bot Token 接入', tokenLabel: 'Bot Token', hasAppId: false },
4989
- { key: 'wechat', icon: '💚', name: '微信', desc: '通过 Token 接入', tokenLabel: 'Token', hasAppId: false }
4990
- ];
4991
- let cardsHtml = '';
4992
- for (const pl of platformList) {
4993
- const enabled = setupPlatforms[pl.key] && setupPlatforms[pl.key].enabled;
4994
- const selCls = enabled ? ' selected' : '';
4995
- cardsHtml += `
4996
- <div class="provider-card${selCls}" id="platCard_${pl.key}" onclick="toggleSetupPlatform('${pl.key}')">
4997
- <div class="provider-icon">${pl.icon}</div>
4998
- <div class="provider-name">${pl.name} ${enabled ? '<span style="color:var(--success);font-size:11px">✓ 已启用</span>' : ''}</div>
4999
- <div class="provider-desc">${pl.desc}</div>
5000
- </div>`;
5001
- }
5002
- // Platform detail form area
5003
- let detailHtml = '';
5004
- for (const pl of platformList) {
5005
- const cfg = setupPlatforms[pl.key] || { enabled: false, token: '', app_id: '' };
5006
- const display = cfg.enabled ? '' : 'display:none';
5007
- detailHtml += `
5008
- <div class="platform-detail" id="platDetail_${pl.key}" style="${display};margin-bottom:16px;padding:16px;border-radius:var(--radius-sm);background:var(--bg2);border:1px solid var(--border)">
5009
- <h4 style="margin:0 0 12px;font-size:14px">${pl.icon} 配置 ${pl.name}</h4>
5010
- ${pl.hasAppId ? `<div class="form-group"><label>App ID</label><input type="text" id="platAppId_${pl.key}" placeholder="填写 App ID" value="${escapeHtml(cfg.app_id || '')}"><div class="form-hint">在 ${pl.name} 开放平台获取</div></div>` : ''}
5011
- <div class="form-group"><label>${pl.tokenLabel}</label><input type="password" id="platToken_${pl.key}" placeholder="填写 ${pl.tokenLabel}" value="${escapeHtml(cfg.token || '')}" autocomplete="off"><div class="form-hint">在 ${pl.name} 开放平台获取</div></div>
5012
- <button class="setup-btn setup-btn-secondary" style="padding:6px 14px;font-size:12px" onclick="setupSavePlatform('${pl.key}')">💾 保存 ${pl.name} 配置</button>
5013
- </div>`;
5014
- }
5015
- wizard.innerHTML = `
5016
- ${renderSetupDots()}
5017
- <h2>🌐 聊天平台接入(可选)</h2>
5018
- <p class="setup-subtitle">将 Agent 接入聊天平台,随时随地与 AI 对话</p>
5019
- <div style="max-height:200px;overflow-y:auto;margin-bottom:16px">${cardsHtml}</div>
5020
- <div id="platformDetailArea">${detailHtml}</div>
5021
- <div class="setup-desc" style="margin-top:8px">
5022
- <p style="font-size:12px;color:var(--text3);line-height:1.7">
5023
- 💡 点击上方平台卡片启用,填写 Token 后保存。可随时在管理后台的「平台配置」中管理。<br>
5024
- 不需要接入平台可跳过此步骤,直接使用 Web 聊天界面。
5025
- </p>
5026
- </div>
5027
- <div class="setup-actions">
5028
- <button class="setup-btn setup-btn-secondary" onclick="setupStep=2;renderSetupStep()">← 上一步</button>
5029
- <button class="setup-btn setup-btn-skip" onclick="setupStep=4;renderSetupStep()">跳过</button>
5030
- <button class="setup-btn setup-btn-primary" onclick="setupStep=4;renderSetupStep()">下一步 →</button>
5031
- </div>`;
5032
- } else if (setupStep === 4) {
5033
4946
  // Done
5034
4947
  const p = SETUP_PROVIDERS[setupProvider];
4948
+ const apiKeyEl = document.getElementById('setupApiKey');
4949
+ const baseUrlEl = document.getElementById('setupBaseUrl');
4950
+ const modelEl = document.getElementById('setupModel');
4951
+ const hasConfig = apiKeyEl && apiKeyEl.value;
5035
4952
  let summaryHtml = '';
5036
- if (p) {
4953
+ if (hasConfig) {
5037
4954
  summaryHtml = `
5038
4955
  <div class="setup-summary">
5039
4956
  <div class="summary-row">
@@ -5041,20 +4958,12 @@ function renderSetupStep() {
5041
4958
  <span class="summary-value">${p.icon} ${p.name}</span>
5042
4959
  </div>
5043
4960
  <div class="summary-row">
5044
- <span class="summary-label">模型</span>
5045
- <span class="summary-value">${escapeHtml(p.model)}</span>
4961
+ <span class="summary-label">Base URL</span>
4962
+ <span class="summary-value">${escapeHtml(baseUrlEl ? baseUrlEl.value : p.base_url)}</span>
5046
4963
  </div>
5047
- </div>`;
5048
- }
5049
- const enabledPlatforms = Object.keys(setupPlatforms).filter(k => setupPlatforms[k].enabled);
5050
- let platformSummary = '';
5051
- if (enabledPlatforms.length > 0) {
5052
- const platformNames = { telegram: '📱 Telegram', discord: '🎮 Discord', feishu: '🐦 飞书', qq: '🐧 QQ', wechat: '💚 微信' };
5053
- platformSummary = `
5054
- <div class="setup-summary" style="margin-top:8px">
5055
4964
  <div class="summary-row">
5056
- <span class="summary-label">已接入平台</span>
5057
- <span class="summary-value">${enabledPlatforms.map(k => platformNames[k] || k).join(', ')}</span>
4965
+ <span class="summary-label">模型</span>
4966
+ <span class="summary-value">${escapeHtml(modelEl ? modelEl.value : p.model)}</span>
5058
4967
  </div>
5059
4968
  </div>`;
5060
4969
  }
@@ -5063,18 +4972,15 @@ function renderSetupStep() {
5063
4972
  <h2>🎉 配置完成!</h2>
5064
4973
  <p class="setup-subtitle">你已准备好开始使用 MyAgent</p>
5065
4974
  ${summaryHtml}
5066
- ${platformSummary}
5067
4975
  <div class="setup-desc">
5068
4976
  <p>💡 <strong>提示:</strong></p>
5069
4977
  <ul style="margin:8px 0 0 20px;line-height:2">
5070
- <li>随时可以在管理后台的「模型设置」中修改 API 配置</li>
5071
- <li>随时可以在管理后台的「平台配置」中管理聊天平台</li>
5072
- <li>点击右侧 Agent 面板中的 🛡️ 配置助手获取更多帮助</li>
4978
+ <li>随时可以在「配置管理」中修改 API 设置</li>
4979
+ <li>点击右侧 Agent 面板中的 🛡️ 配置助手获取帮助</li>
5073
4980
  <li>使用 <kbd style="padding:2px 6px;background:var(--bg3);border-radius:3px;font-size:11px">Ctrl+N</kbd> 快速创建新对话</li>
5074
4981
  </ul>
5075
4982
  </div>
5076
4983
  <div class="setup-actions">
5077
- <button class="setup-btn setup-btn-secondary" onclick="setupStep=3;renderSetupStep()">← 上一步</button>
5078
4984
  <button class="setup-btn setup-btn-primary" onclick="skipSetup()">🚀 开始使用</button>
5079
4985
  </div>`;
5080
4986
  }
@@ -5089,121 +4995,6 @@ function selectSetupProvider(key) {
5089
4995
  event.currentTarget.classList.add('selected');
5090
4996
  }
5091
4997
 
5092
- function toggleSetupPlatform(key) {
5093
- if (!setupPlatforms[key]) {
5094
- setupPlatforms[key] = { enabled: false, token: '', app_id: '' };
5095
- }
5096
- setupPlatforms[key].enabled = !setupPlatforms[key].enabled;
5097
- // Toggle card style and detail area
5098
- const card = document.getElementById('platCard_' + key);
5099
- const detail = document.getElementById('platDetail_' + key);
5100
- if (card) {
5101
- card.classList.toggle('selected', setupPlatforms[key].enabled);
5102
- // Update name to show checkmark
5103
- const nameEl = card.querySelector('.provider-name');
5104
- if (nameEl) {
5105
- const baseName = nameEl.textContent.replace(/ ✓ 已启用| ✓ 已启用/, '').replace(/[✓ 已启用]/g, '').trim();
5106
- nameEl.innerHTML = baseName + (setupPlatforms[key].enabled ? ' <span style="color:var(--success);font-size:11px">✓ 已启用</span>' : '');
5107
- }
5108
- }
5109
- if (detail) {
5110
- detail.style.display = setupPlatforms[key].enabled ? '' : 'none';
5111
- }
5112
- }
5113
-
5114
- async function setupSavePlatform(key) {
5115
- const tokenEl = document.getElementById('platToken_' + key);
5116
- const appIdEl = document.getElementById('platAppId_' + key);
5117
- const token = tokenEl ? tokenEl.value.trim() : '';
5118
- const appId = appIdEl ? appIdEl.value.trim() : '';
5119
-
5120
- if (!token && !appId) {
5121
- showToast('请至少填写 Token 或 App ID', 'warning');
5122
- return;
5123
- }
5124
-
5125
- try {
5126
- const body = { platform: key, token: token, enabled: true };
5127
- if (appId) body.app_id = appId;
5128
- const r = await api('/api/platforms', { method: 'POST', body: JSON.stringify(body) });
5129
- if (r.error) {
5130
- showToast('保存失败:' + r.error, 'danger');
5131
- return;
5132
- }
5133
- // Update local state
5134
- setupPlatforms[key].token = token;
5135
- setupPlatforms[key].app_id = appId;
5136
- showToast('已保存 ' + key + ' 平台配置', 'success');
5137
- } catch (e) {
5138
- showToast('保存失败:' + (e.message || '网络错误'), 'danger');
5139
- }
5140
- }
5141
-
5142
- async function setupSaveLLMAndNext() {
5143
- // Same logic as setupSaveAndComplete, but goes to platform step instead of done
5144
- const statusEl = document.getElementById('setupStatus');
5145
- const apiKey = document.getElementById('setupApiKey').value;
5146
- const baseUrl = document.getElementById('setupBaseUrl').value;
5147
- const model = document.getElementById('setupModel').value;
5148
- const customNameEl = document.getElementById('setupCustomName');
5149
- const customName = customNameEl ? customNameEl.value.trim() : '';
5150
- const p = SETUP_PROVIDERS[setupProvider];
5151
- const isCustom = !!p.is_custom;
5152
-
5153
- if (isCustom && (!baseUrl || !model)) {
5154
- if (statusEl) {
5155
- statusEl.className = 'setup-status show error';
5156
- statusEl.innerHTML = '❌ 自定义模型必须填写 Base URL 和模型名称';
5157
- }
5158
- return;
5159
- }
5160
-
5161
- try {
5162
- const provider = isCustom ? 'custom' : setupProvider;
5163
- await api('/api/llm', {
5164
- method: 'PUT',
5165
- body: JSON.stringify({ api_key: apiKey, base_url: baseUrl, model: model, provider: provider })
5166
- });
5167
-
5168
- // Also add to model library
5169
- const modelId = 'custom-' + model.replace(/[^a-zA-Z0-9._-]/g, '-').toLowerCase();
5170
- const modelDisplayName = isCustom && customName
5171
- ? customName
5172
- : (p.name + ' - ' + model);
5173
- try {
5174
- await api('/api/models', {
5175
- method: 'POST',
5176
- body: JSON.stringify({
5177
- id: modelId,
5178
- name: modelDisplayName,
5179
- provider: provider,
5180
- model: model,
5181
- base_url: baseUrl,
5182
- api_key: apiKey,
5183
- max_tokens: 4096,
5184
- temperature: 0.1,
5185
- enabled: true
5186
- })
5187
- });
5188
- } catch (modelErr) {
5189
- console.warn('Failed to add model to library:', modelErr);
5190
- }
5191
-
5192
- await api('/api/setup/complete', { method: 'POST' });
5193
- StatePersistence.markSetupDone();
5194
- loadStatus();
5195
- loadModels();
5196
- // Go to platform step instead of done
5197
- setupStep = 3;
5198
- renderSetupStep();
5199
- } catch (e) {
5200
- if (statusEl) {
5201
- statusEl.className = 'setup-status show error';
5202
- statusEl.innerHTML = '❌ 保存失败:' + escapeHtml(e.message || '未知错误');
5203
- }
5204
- }
5205
- }
5206
-
5207
4998
  async function setupTestConnection() {
5208
4999
  const statusEl = document.getElementById('setupStatus');
5209
5000
  if (!statusEl) return;
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ ---
2
+ Task ID: 2
3
+ Agent: main
4
+ Task: 创建 ToolDispatcher + 重构工具分发 + Skill Prompt 按需加载
5
+
6
+ Stage Summary:
7
+ - 新文件: myagent/core/tool_dispatcher.py (438行)
8
+ - main_agent.py: 1895→1557行 (-338行), 替换 _execute_v2_tool 为 dispatcher.dispatch()
9
+ - main.py: 初始化 ToolDispatcher, 添加 _sync_skill_guides_to_knowledge()
10
+ - context_builder.py: _build_skill_prompts() 返回空字符串
11
+ - SYSTEM_PROMPT: 移除 code/command_run, 添加专业技能指令 get_knowledge 说明
12
+ - 修复 _safe_sse NameError bug
@@ -102,3 +102,47 @@ Stage Summary:
102
102
  - 版本: 1.25.1 → 1.25.2
103
103
  - npm: myagent-ai@1.25.2 已发布
104
104
  - GitHub: 已推送到 ctz168/myagent main 分支 (commit 9f7409a, 49de298)
105
+ ---
106
+ Task ID: 1
107
+ Agent: main
108
+ Task: 完善 webcontrol 工具 - 人机交互登录增强 (v1.25.4)
109
+
110
+ Work Log:
111
+ - 调查现有 webcontrol 实现(myagent/core/web_control.py, tool_dispatcher.py, api_server.py, chat_main.js)
112
+ - 设计增强方案:login 一站式登录流程 + 凭证管理 + UI 优化
113
+ - 修改 myagent/core/web_control.py:新增 LOGIN_URLS 平台模板(18个平台),增强 CONTROL_SCRIPT 人机模式(URL变化检测/平台名显示),新增 save_credentials_to_file/list_credentials/delete_credentials 方法
114
+ - 修改 myagent/core/tool_dispatcher.py:新增 login action(一站式登录流程),新增 save_credentials/list_credentials/delete_credentials action
115
+ - 修改 myagent/skills/registry.py:更新 web_control 工具 schema,新增4个action + platform参数
116
+ - 修改 myagent/web/api_server.py:面板UI增强(倒计时/备注弹窗/刷新QR码按钮/login事件处理)
117
+ - 修改 myagent/web/ui/chat/chat_main.js:新增 login/login_done SSE 事件处理 + 历史消息渲染
118
+ - 同步 root/core/ 文件
119
+ - 更新版本号到 1.25.4
120
+ - 推送 GitHub + 发布 npm
121
+
122
+ Stage Summary:
123
+ - 已发布 v1.25.4
124
+ - 新增 4 个 web_control action: login, save_credentials, list_credentials, delete_credentials
125
+ - 18 个预置平台登录 URL (QQ/微信/Telegram/Discord/飞书/钉钉/GitHub/Google/B站/淘宝/知乎/微博等)
126
+ - 凭证管理: 自动保存 cookies 到 ~/.myagent/data/credentials/
127
+ - 面板增强: 倒计时显示(最后30秒变红)、备注弹窗、刷新QR码按钮
128
+ - 登录检测: URL 变化自动通知(登录成功判断)
129
+ ---
130
+ Task ID: 1
131
+ Agent: main
132
+ Task: 修复严重事故 - v1.25.2/v1.25.4 升级导致版本降级
133
+
134
+ Work Log:
135
+ - 检查 npm registry 确认最新版本为 1.25.4
136
+ - 克隆 GitHub 仓库,对比 v1.25.1 和 v1.25.4 的包内容
137
+ - 发现 v1.25.4 npm 包根目录缺少 start.js、start.sh、web/ 目录
138
+ - 定位根因: commit 9f7409a (v1.25.2 准备) 意外删除了根目录的 start.js、start.sh、web/ 等关键文件
139
+ - 这些文件仅存在于 myagent/ 子目录下(npm 包内),但 package.json 的 bin 入口指向根目录
140
+ - 从 v1.25.1 恢复 start.js/start.sh,从 v1.25.4 npm 包的 myagent/ 子目录恢复 web/(含 setup wizard 平台接入改动)
141
+ - 更新版本号到 1.25.5,提交并推送到 GitHub
142
+ - 成功发布 v1.25.5 到 npm registry
143
+
144
+ Stage Summary:
145
+ - 根因: commit 9f7409a 意外删除了根目录的 start.js、start.sh、web/ 目录
146
+ - 影响: v1.25.2-v1.25.4 的 npm 包 bin 入口断裂,升级后回退到旧版本
147
+ - 修复: v1.25.5 已发布到 npm,恢复所有关键文件
148
+ - 用户可通过 `npm install -g myagent-ai@latest --force` 修复
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.25.7",
3
+ "version": "1.25.9",
4
4
  "description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
5
5
  "main": "main.py",
6
6
  "bin": {