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.
- package/core/version.py +36 -10
- package/myagent/core/version.py +36 -10
- package/myagent/main.py +4 -3
- package/myagent/package.json +1 -1
- package/myagent/start.sh +0 -0
- package/myagent/web/__init__.py +0 -0
- package/myagent/web/api_server.py +0 -227
- package/myagent/web/tts_handler.py +0 -0
- package/myagent/web/ui/admin/admin-agentchat.js +0 -0
- package/myagent/web/ui/admin/admin-agents.js +0 -0
- package/myagent/web/ui/admin/admin-core.js +0 -0
- package/myagent/web/ui/admin/admin-dashboard.js +0 -0
- package/myagent/web/ui/admin/admin-executor.js +0 -0
- package/myagent/web/ui/admin/admin-files.js +0 -0
- package/myagent/web/ui/admin/admin-llm.js +0 -0
- package/myagent/web/ui/admin/admin-logs.js +0 -0
- package/myagent/web/ui/admin/admin-memory.js +0 -0
- package/myagent/web/ui/admin/admin-org.js +0 -0
- package/myagent/web/ui/admin/admin-permissions.js +0 -0
- package/myagent/web/ui/admin/admin-platforms.js +0 -0
- package/myagent/web/ui/admin/admin-sessions.js +0 -0
- package/myagent/web/ui/admin/admin-skills.js +0 -0
- package/myagent/web/ui/admin/admin-system.js +0 -0
- package/myagent/web/ui/admin/admin-tasks.js +0 -0
- package/myagent/web/ui/chat/chat.css +0 -0
- package/myagent/web/ui/chat/chat.js +0 -0
- package/myagent/web/ui/chat/chat_container.html +0 -0
- package/myagent/web/ui/chat/chat_main.js +15 -224
- package/myagent/web/ui/chat/flow_engine.js +0 -0
- package/myagent/web/ui/chat/groupchat.js +0 -0
- package/myagent/web/ui/chat/left_sessions.html +0 -0
- package/myagent/web/ui/chat/middle_chat.html +0 -0
- package/myagent/web/ui/chat/right_agents.html +0 -0
- package/myagent/web/ui/index.html +0 -0
- package/myagent/worklog-v1.22.md +12 -0
- package/myagent/worklog.md +44 -0
- 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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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/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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
package/myagent/package.json
CHANGED
package/myagent/start.sh
CHANGED
|
File without changes
|
package/myagent/web/__init__.py
CHANGED
|
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">🎯 请在上方页面完成登录或验证操作...</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="刷新页面(重新获取二维码)">🔄 刷新</button>
|
|
1721
|
-
<button class="wc-btn-human-cancel" onclick="wcHumanCancel()">❌ 取消</button>
|
|
1722
|
-
<button class="wc-btn-human-done" onclick="wcHumanDone()">✅ 完成登录</button>
|
|
1723
|
-
</div>
|
|
1724
|
-
|
|
1725
|
-
<!-- [v1.25.4] 人机交互备注弹窗 -->
|
|
1726
|
-
<div class="wc-overlay" id="wcNoteOverlay">
|
|
1727
|
-
<div class="wc-modal">
|
|
1728
|
-
<h3>📝 操作备注 (可选)</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:
|
|
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 <
|
|
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=
|
|
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="
|
|
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 (
|
|
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"
|
|
5045
|
-
<span class="summary-value">${escapeHtml(p.
|
|
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"
|
|
5057
|
-
<span class="summary-value">${
|
|
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
|
|
5071
|
-
<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
|
package/myagent/worklog.md
CHANGED
|
@@ -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` 修复
|