myagent-ai 1.32.6 → 1.32.8
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/agents/main_agent.py +1 -1
- package/memory/manager.py +8 -7
- package/package.json +1 -1
- package/web/api_server.py +29 -56
- package/web/ui/admin/admin-agents.js +11 -3
- package/web/ui/admin/admin-core.js +7 -7
- package/web/ui/chat/chat_main.js +23 -91
- package/web/ui/chat/flow_engine.js +1 -1
- package/web/ui/chat/groupchat.js +11 -8
package/agents/main_agent.py
CHANGED
|
@@ -221,7 +221,7 @@ class MainAgent(BaseAgent):
|
|
|
221
221
|
try:
|
|
222
222
|
self.agent_id = self.memory.get_agent_id(self.name)
|
|
223
223
|
except Exception:
|
|
224
|
-
self.agent_id =
|
|
224
|
+
self.agent_id = 1
|
|
225
225
|
|
|
226
226
|
def init_context_builder(self, memory_manager=None, skill_registry=None, knowledge_base_dir=None, context_window=None):
|
|
227
227
|
"""初始化 Context Builder(在系统启动后调用,注入依赖)"""
|
package/memory/manager.py
CHANGED
|
@@ -35,8 +35,8 @@ logger = get_logger("myagent.memory")
|
|
|
35
35
|
class MemoryEntry:
|
|
36
36
|
"""记忆条目"""
|
|
37
37
|
id: str = field(default_factory=lambda: generate_id("mem"))
|
|
38
|
-
session_id: str = "
|
|
39
|
-
agent_id: int =
|
|
38
|
+
session_id: str = ""
|
|
39
|
+
agent_id: int = 1 # 所属agent ID(数字ID,从1开始,1=全权Agent)
|
|
40
40
|
category: str = "session" # session | global
|
|
41
41
|
key: str = "" # 检索键/标签
|
|
42
42
|
content: str = "" # 记忆内容
|
|
@@ -66,7 +66,7 @@ class MemoryEntry:
|
|
|
66
66
|
return cls(
|
|
67
67
|
id=row["id"],
|
|
68
68
|
session_id=row["session_id"],
|
|
69
|
-
agent_id=int(dict(row).get("agent_id",
|
|
69
|
+
agent_id=int(dict(row).get("agent_id", 1) or 1),
|
|
70
70
|
category=row["category"],
|
|
71
71
|
key=row["key"],
|
|
72
72
|
content=row["content"],
|
|
@@ -147,14 +147,14 @@ class MemoryManager:
|
|
|
147
147
|
from datetime import datetime as _dt
|
|
148
148
|
from core.utils import get_config_tz
|
|
149
149
|
now = _dt.now(get_config_tz()).strftime("%Y-%m-%d %H:%M:%S")
|
|
150
|
-
conn.execute("INSERT OR IGNORE INTO agents (id, name, created_at) VALUES (1, '
|
|
150
|
+
conn.execute("INSERT OR IGNORE INTO agents (id, name, created_at) VALUES (1, '1', ?)", (now,))
|
|
151
151
|
|
|
152
152
|
# 创建 memories 表
|
|
153
153
|
conn.executescript("""
|
|
154
154
|
CREATE TABLE IF NOT EXISTS memories (
|
|
155
155
|
id TEXT PRIMARY KEY,
|
|
156
156
|
session_id TEXT NOT NULL,
|
|
157
|
-
agent_id INTEGER NOT NULL DEFAULT
|
|
157
|
+
agent_id INTEGER NOT NULL DEFAULT 1,
|
|
158
158
|
category TEXT NOT NULL,
|
|
159
159
|
key TEXT DEFAULT '',
|
|
160
160
|
content TEXT DEFAULT '',
|
|
@@ -207,7 +207,8 @@ class MemoryManager:
|
|
|
207
207
|
return cursor.lastrowid
|
|
208
208
|
except Exception as e:
|
|
209
209
|
logger.error(f"获取 agent ID 失败: {e}")
|
|
210
|
-
|
|
210
|
+
# 返回 1 作为兜底(全权Agent),避免 agent_id=0 导致数据归属不明
|
|
211
|
+
return 1
|
|
211
212
|
|
|
212
213
|
def register_agent(self, agent_name: str) -> int:
|
|
213
214
|
"""注册新 agent,返回分配的 ID"""
|
|
@@ -333,7 +334,7 @@ class MemoryManager:
|
|
|
333
334
|
# 会话记忆 (session) — 对话上下文 + 任务进度
|
|
334
335
|
# ==========================================================================
|
|
335
336
|
|
|
336
|
-
def add_session(self, session_id, agent_id=
|
|
337
|
+
def add_session(self, session_id, agent_id=1, role="", content="", key="", importance=0.5, metadata=None) -> str:
|
|
337
338
|
"""添加会话记忆。内容不包含时间前缀,时间仅存于 created_at 和 metadata。"""
|
|
338
339
|
from datetime import datetime as _dt
|
|
339
340
|
from core.utils import get_config_tz
|
package/package.json
CHANGED
package/web/api_server.py
CHANGED
|
@@ -1896,8 +1896,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
1896
1896
|
agent_path = data.get("agent_path", agent_name)
|
|
1897
1897
|
# 获取数字 agent_id
|
|
1898
1898
|
agent_id = self.core.memory.get_agent_id(agent_path)
|
|
1899
|
-
|
|
1900
|
-
session_id = data.get("sid", "") or data.get("session_id", "") or "web_default"
|
|
1899
|
+
session_id = data.get("sid", "") or data.get("session_id", "")
|
|
1901
1900
|
chat_mode = data.get("mode", "") # "exec" = 执行模式
|
|
1902
1901
|
escalated = data.get("escalated", False) # 临时提权到 local
|
|
1903
1902
|
|
|
@@ -2056,8 +2055,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2056
2055
|
return web.Response(text="data: " + json.dumps({"error": "message is required"}) + "\n\n", content_type="text/event-stream")
|
|
2057
2056
|
|
|
2058
2057
|
agent_path = data.get("agent_path", data.get("agent_name", "1")) or "1"
|
|
2059
|
-
|
|
2060
|
-
session_id = data.get("sid", "") or data.get("session_id", "") or "web_default"
|
|
2058
|
+
session_id = data.get("sid", "") or data.get("session_id", "")
|
|
2061
2059
|
chat_mode = data.get("mode", "")
|
|
2062
2060
|
escalated = data.get("escalated", False)
|
|
2063
2061
|
voice_text = data.get("voice_text", "").strip() # 语音转文字原始文本(用于 usersays_correct)
|
|
@@ -2191,7 +2189,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2191
2189
|
"""后台任务:即使 SSE 断开也完整执行并保存结果"""
|
|
2192
2190
|
logger.info(f"[{session_id}] _run_stream_task 开始执行")
|
|
2193
2191
|
# [v1.32.2] 安全修复: 定义 agent_id,避免 except 块中引用时 NameError
|
|
2194
|
-
_stream_agent_id = self.core.memory.get_agent_id(agent_path) if self.core.memory and agent_path else
|
|
2192
|
+
_stream_agent_id = self.core.memory.get_agent_id(agent_path) if self.core.memory and agent_path else 1
|
|
2195
2193
|
try:
|
|
2196
2194
|
agent_cfg = self._read_agent_config(agent_path)
|
|
2197
2195
|
model_chain = self._build_model_chain(agent_cfg, agent_path)
|
|
@@ -2449,8 +2447,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2449
2447
|
return web.json_response({"error": "message is required"}, status=400)
|
|
2450
2448
|
|
|
2451
2449
|
agent_path = data.get("agent_path", "1") or "1"
|
|
2452
|
-
|
|
2453
|
-
session_id = data.get("sid", "") or data.get("session_id", "web_default")
|
|
2450
|
+
session_id = data.get("sid", "") or data.get("session_id", "")
|
|
2454
2451
|
choice = data.get("choice", "queue") # "continue" (插入后继续) 或 "queue" (排队)
|
|
2455
2452
|
|
|
2456
2453
|
# 检查会话是否正在运行
|
|
@@ -3834,12 +3831,12 @@ window.addEventListener('beforeunload', function() {{
|
|
|
3834
3831
|
# 清理该 Agent 相关的会话和记忆数据
|
|
3835
3832
|
if self.core.memory:
|
|
3836
3833
|
try:
|
|
3837
|
-
#
|
|
3834
|
+
# 删除该 agent 的所有会话(通过 agent_id 精确匹配)
|
|
3838
3835
|
conn = self.core.memory._get_conn()
|
|
3839
|
-
|
|
3836
|
+
target_aid = self.core.memory.get_agent_id(path)
|
|
3840
3837
|
rows = conn.execute(
|
|
3841
|
-
"SELECT DISTINCT session_id FROM memories WHERE
|
|
3842
|
-
(
|
|
3838
|
+
"SELECT DISTINCT session_id FROM memories WHERE agent_id = ?",
|
|
3839
|
+
(target_aid,),
|
|
3843
3840
|
).fetchall()
|
|
3844
3841
|
for row in rows:
|
|
3845
3842
|
sid = row["session_id"]
|
|
@@ -4329,34 +4326,22 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4329
4326
|
_hidden = '(' + ','.join(["'llm_output'", "'llm_input'", "'tool_result_raw'", "'conversation_insight'"]) + ')'
|
|
4330
4327
|
# 只统计用户可见的消息数(排除 llm_output 和 conversation_insight)
|
|
4331
4328
|
if agent:
|
|
4332
|
-
#
|
|
4333
|
-
target_aid = self.core.memory.get_agent_id(agent)
|
|
4334
|
-
#
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
GROUP BY session_id ORDER BY last DESC LIMIT 100""",
|
|
4344
|
-
(target_aid,)).fetchall()
|
|
4345
|
-
else:
|
|
4346
|
-
# 其他 agent: agent_id=数字ID 或 session_id 前缀匹配(旧数据)
|
|
4347
|
-
rows = conn.execute(
|
|
4348
|
-
f"""SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last,
|
|
4349
|
-
MAX(CASE WHEN agent_id != ? THEN agent_id ELSE NULL END) as raw_agent_id FROM memories
|
|
4350
|
-
WHERE category = 'session' AND role != ''
|
|
4351
|
-
AND key NOT IN {_hidden}
|
|
4352
|
-
AND (agent_id = ? OR session_id LIKE ?)
|
|
4353
|
-
GROUP BY session_id ORDER BY last DESC LIMIT 100""",
|
|
4354
|
-
(target_aid, target_aid, f"{agent}_%")).fetchall()
|
|
4329
|
+
# 将 agent 路径转为数字 ID,精确过滤
|
|
4330
|
+
target_aid = self.core.memory.get_agent_id(agent)
|
|
4331
|
+
# 统一使用 agent_id 精确匹配
|
|
4332
|
+
rows = conn.execute(
|
|
4333
|
+
f"""SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last,
|
|
4334
|
+
agent_id as raw_agent_id FROM memories
|
|
4335
|
+
WHERE category = 'session' AND role != ''
|
|
4336
|
+
AND key NOT IN {_hidden}
|
|
4337
|
+
AND agent_id = ?
|
|
4338
|
+
GROUP BY session_id ORDER BY last DESC LIMIT 100""",
|
|
4339
|
+
(target_aid,)).fetchall()
|
|
4355
4340
|
else:
|
|
4356
4341
|
# [v1.27.2] 无 agent 过滤时也返回 agent_id,供后台管理页面使用
|
|
4357
4342
|
rows = conn.execute(
|
|
4358
4343
|
f"SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last, "
|
|
4359
|
-
f"
|
|
4344
|
+
f"agent_id as raw_agent_id FROM memories "
|
|
4360
4345
|
f"WHERE category = 'session' AND role != '' "
|
|
4361
4346
|
f"AND key NOT IN {_hidden} "
|
|
4362
4347
|
f"GROUP BY session_id ORDER BY last DESC LIMIT 100").fetchall()
|
|
@@ -4369,7 +4354,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4369
4354
|
agent_name = _agent_id_map.get(int(raw_aid), "")
|
|
4370
4355
|
sessions.append({"id": r["session_id"], "messages": r["cnt"], "last": r["last"],
|
|
4371
4356
|
"agent_id": agent_name, # 返回 agent 名称(非数字 ID)
|
|
4372
|
-
"agent_db_id":
|
|
4357
|
+
"agent_db_id": int(raw_aid), # 数字 ID 供 URL 使用
|
|
4373
4358
|
"display_name": "", "preview": ""})
|
|
4374
4359
|
# 批量获取自定义会话名称
|
|
4375
4360
|
sids = [s["id"] for s in sessions]
|
|
@@ -4399,25 +4384,13 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4399
4384
|
name = request.match_info["name"]
|
|
4400
4385
|
if not self.core.memory:
|
|
4401
4386
|
return web.json_response({"agent": name, "sessions": []})
|
|
4402
|
-
#
|
|
4387
|
+
# 使用数字 agent_id 精确过滤
|
|
4403
4388
|
target_aid = self.core.memory.get_agent_id(name)
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
WHERE category = 'session'
|
|
4410
|
-
AND (agent_id = 0 OR agent_id = ? OR session_id = 'web_default' OR session_id LIKE 'sess_%')
|
|
4411
|
-
GROUP BY session_id ORDER BY last DESC LIMIT 100""",
|
|
4412
|
-
(target_aid,)).fetchall()
|
|
4413
|
-
else:
|
|
4414
|
-
# 其他 agent: agent_id=数字ID 或 session_id 前缀匹配(旧数据)
|
|
4415
|
-
rows = self.core.memory._get_conn().execute(
|
|
4416
|
-
"""SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last FROM memories
|
|
4417
|
-
WHERE category = 'session'
|
|
4418
|
-
AND (agent_id = ? OR session_id LIKE ?)
|
|
4419
|
-
GROUP BY session_id ORDER BY last DESC LIMIT 100""",
|
|
4420
|
-
(target_aid, f"{name}_%")).fetchall()
|
|
4389
|
+
rows = self.core.memory._get_conn().execute(
|
|
4390
|
+
"""SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last FROM memories
|
|
4391
|
+
WHERE category = 'session' AND agent_id = ?
|
|
4392
|
+
GROUP BY session_id ORDER BY last DESC LIMIT 100""",
|
|
4393
|
+
(target_aid,)).fetchall()
|
|
4421
4394
|
sessions = [{"id": r["session_id"], "messages": r["cnt"], "last": r["last"]} for r in rows]
|
|
4422
4395
|
# 批量获取自定义会话名称
|
|
4423
4396
|
sids = [s["id"] for s in sessions]
|
|
@@ -6140,7 +6113,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
6140
6113
|
context.metadata["user_voice_text"] = voice_text # 语音输入原始文本(用于 usersays_correct)
|
|
6141
6114
|
|
|
6142
6115
|
# [v1.28] 传入正确的 agent_db_id,确保 V2 路径保存会话时使用正确的 agent_id
|
|
6143
|
-
agent_id =
|
|
6116
|
+
agent_id = 1 # 默认为全权Agent
|
|
6144
6117
|
if agent_path and self.core.memory:
|
|
6145
6118
|
agent_id = self.core.memory.get_agent_id(agent_path)
|
|
6146
6119
|
context.metadata["agent_db_id"] = agent_id
|
|
@@ -6390,7 +6363,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
6390
6363
|
recent = agent.memory.get_conversation(session_id, limit=3)
|
|
6391
6364
|
_has_assistant = any(e.role == "assistant" for e in recent)
|
|
6392
6365
|
if not _has_assistant and final_response and final_response.strip():
|
|
6393
|
-
_fallback_agent_id = context.metadata.get("agent_db_id",
|
|
6366
|
+
_fallback_agent_id = context.metadata.get("agent_db_id", 1)
|
|
6394
6367
|
agent.memory.add_session(agent_id=_fallback_agent_id,
|
|
6395
6368
|
session_id=session_id, role="assistant", content=final_response,
|
|
6396
6369
|
)
|
|
@@ -556,10 +556,18 @@ function confirmDeleteAgent(path,name){
|
|
|
556
556
|
});
|
|
557
557
|
}
|
|
558
558
|
|
|
559
|
-
// 直接以执行模式打开与指定 Agent
|
|
560
|
-
// [v1.27.2] 使用 a 参数(UrlCodec 编码),不再明文暴露 agent 路径
|
|
559
|
+
// 直接以执行模式打开与指定 Agent 的对话(使用 aid 数字 ID)
|
|
561
560
|
function chatWithAgent(path){
|
|
562
|
-
|
|
561
|
+
// 查找该 agent 的数字 ID
|
|
562
|
+
var _aid = null;
|
|
563
|
+
if (typeof allAgentsCache !== 'undefined' && Array.isArray(allAgentsCache)) {
|
|
564
|
+
for (var i = 0; i < allAgentsCache.length; i++) {
|
|
565
|
+
if (allAgentsCache[i].path === path) { _aid = allAgentsCache[i].aid; break; }
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
var url = '/ui/chat/chat_container.html?mode=exec';
|
|
569
|
+
if (_aid) url += '&aid=' + _aid;
|
|
570
|
+
window.location.href = url;
|
|
563
571
|
}
|
|
564
572
|
|
|
565
573
|
if (typeof window._adminRenderers === 'undefined') window._adminRenderers = {};
|
|
@@ -158,26 +158,26 @@ document.getElementById('adminSidebar')?.addEventListener('click',function(e){
|
|
|
158
158
|
loadVersion();
|
|
159
159
|
setTimeout(()=>checkUpdate(false),30000);
|
|
160
160
|
|
|
161
|
-
//
|
|
161
|
+
// 返回聊天:通过 aid(数字 agent ID)和 session 参数恢复
|
|
162
162
|
(function(){
|
|
163
163
|
function _buildReturnUrl(){
|
|
164
164
|
var params=new URLSearchParams(window.location.search);
|
|
165
165
|
var base='/ui/chat/chat_container.html';
|
|
166
|
-
// 从 URL
|
|
167
|
-
var
|
|
166
|
+
// 从 URL 参数中恢复聊天状态(统一使用 aid 数字 ID)
|
|
167
|
+
var aid=params.get('from_aid');
|
|
168
168
|
var session=params.get('from_session');
|
|
169
|
-
//
|
|
170
|
-
var groupSession=params.get('
|
|
169
|
+
// 群聊纯数字 session ID(优先级最高,覆盖 ?s= 个人会话参数)
|
|
170
|
+
var groupSession=params.get('from_g');
|
|
171
171
|
var mode=params.get('from_mode');
|
|
172
172
|
var parts=[];
|
|
173
173
|
// 如果有群聊 session,用 ?g= 参数(纯数字 ID)
|
|
174
174
|
if(groupSession && /^[0-9]+$/.test(groupSession)){
|
|
175
175
|
parts.push('g='+groupSession);
|
|
176
|
-
if(
|
|
176
|
+
if(aid)parts.push('aid='+aid);
|
|
177
177
|
if(mode)parts.push('mode='+encodeURIComponent(mode));
|
|
178
178
|
} else {
|
|
179
179
|
// 个人聊天模式
|
|
180
|
-
if(
|
|
180
|
+
if(aid)parts.push('aid='+aid);
|
|
181
181
|
if(mode)parts.push('mode='+encodeURIComponent(mode));
|
|
182
182
|
if(session)parts.push('s='+encodeURIComponent(session));
|
|
183
183
|
}
|
package/web/ui/chat/chat_main.js
CHANGED
|
@@ -86,19 +86,20 @@ function closeMobileAgentPanel() {
|
|
|
86
86
|
if (overlay) overlay.classList.remove('active');
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
//
|
|
89
|
+
// 跳转后台管理:携带当前聊天上下文(aid数字ID、session、群聊ID),以便"返回聊天"正确恢复
|
|
90
90
|
function goToAdmin() {
|
|
91
91
|
var params = new URLSearchParams();
|
|
92
92
|
var page = 'dashboard';
|
|
93
|
-
// 传递当前聊天状态,供"返回聊天"
|
|
94
|
-
|
|
93
|
+
// 传递当前聊天状态,供"返回聊天"恢复(统一使用 aid 数字 ID)
|
|
94
|
+
var _curAgentObj = findAgentByPath(state.activeAgent);
|
|
95
|
+
if (_curAgentObj && _curAgentObj.aid) params.set('from_aid', _curAgentObj.aid);
|
|
95
96
|
if (state.chatMode) params.set('from_mode', state.chatMode);
|
|
96
97
|
if (state.activeSessionId && currentView !== 'group') params.set('from_session', state.activeSessionId);
|
|
97
|
-
//
|
|
98
|
+
// 传递群聊纯数字 session ID(从 URL 读取)
|
|
98
99
|
if (typeof currentView !== 'undefined' && currentView === 'group') {
|
|
99
100
|
var urlP = new URLSearchParams(window.location.search);
|
|
100
101
|
var gSession = urlP.get('g');
|
|
101
|
-
if (gSession) params.set('
|
|
102
|
+
if (gSession) params.set('from_g', gSession);
|
|
102
103
|
}
|
|
103
104
|
// 保留原始 ?page= 参数
|
|
104
105
|
var origParams = new URLSearchParams(window.location.search);
|
|
@@ -356,10 +357,7 @@ const StatePersistence = {
|
|
|
356
357
|
if (savedSessionId) {
|
|
357
358
|
state._pendingSessionRestore = savedSessionId;
|
|
358
359
|
}
|
|
359
|
-
//
|
|
360
|
-
// 仅保留兼容处理:如果旧版遗留了 localStorage 群聊状态,清除它
|
|
361
|
-
StatePersistence.remove('currentView');
|
|
362
|
-
StatePersistence.remove('currentGroupId');
|
|
360
|
+
// 群聊状态统一由 URL ?g= 参数恢复,不从 localStorage 恢复
|
|
363
361
|
},
|
|
364
362
|
/** 标记 setup 已完成(避免每次刷新弹出向导) */
|
|
365
363
|
markSetupDone() { StatePersistence.save('setupDone', true); },
|
|
@@ -376,19 +374,13 @@ async function initChat() {
|
|
|
376
374
|
initAttachmentUI();
|
|
377
375
|
|
|
378
376
|
// URL 参数处理: ?aid=数字ID&mode=exec&s=编码session&g=群聊ID&popout=1
|
|
379
|
-
// [v1.27.2] 使用 aid(数字 agent ID)代替明文 agent 名字
|
|
380
377
|
const urlParams = new URLSearchParams(window.location.search);
|
|
381
378
|
const urlAid = parseInt(urlParams.get('aid') || '', 10) || 0;
|
|
382
|
-
// 兼容旧格式 ?a= 编码 或 ?agent= 明文
|
|
383
|
-
const urlAgentLegacy = UrlCodec.decode(urlParams.get('a') || '') || UrlCodec.decode(urlParams.get('agent') || '');
|
|
384
379
|
const urlMode = urlParams.get('mode');
|
|
385
|
-
const urlSession = UrlCodec.decode(urlParams.get('s') || '')
|
|
380
|
+
const urlSession = UrlCodec.decode(urlParams.get('s') || '');
|
|
386
381
|
const isPopout = urlParams.get('popout') === '1';
|
|
387
|
-
//
|
|
382
|
+
// 群聊纯数字 session ID(?g= 参数,优先级最高)
|
|
388
383
|
const urlGroupSession = urlParams.get('g') || '';
|
|
389
|
-
// 兼容旧版 ?group= 参数(从后台管理返回时的旧格式)
|
|
390
|
-
const urlGroupSessionLegacy = urlParams.get('from_group_session') || '';
|
|
391
|
-
const _effectiveGroupSession = urlGroupSession || urlGroupSessionLegacy;
|
|
392
384
|
if (urlMode === 'chat' || urlMode === 'exec') {
|
|
393
385
|
state.chatMode = urlMode;
|
|
394
386
|
}
|
|
@@ -473,26 +465,11 @@ async function initChat() {
|
|
|
473
465
|
state.agentsFlat.forEach(function(a) {
|
|
474
466
|
if (a.aid) _aidToPath[a.aid] = a.path;
|
|
475
467
|
});
|
|
476
|
-
// 从 URL 解析 agent:
|
|
468
|
+
// 从 URL 解析 agent: 仅支持 aid(数字 agent ID)
|
|
477
469
|
var urlAgent = '';
|
|
478
470
|
if (urlAid && _aidToPath[urlAid]) {
|
|
479
471
|
urlAgent = _aidToPath[urlAid];
|
|
480
|
-
} else if (urlAgentLegacy) {
|
|
481
|
-
urlAgent = urlAgentLegacy;
|
|
482
472
|
}
|
|
483
|
-
// 清理 URL 中的旧格式参数(agent/a/session),统一使用 aid/s
|
|
484
|
-
try {
|
|
485
|
-
var _cleanUrl = new URL(window.location.href);
|
|
486
|
-
_cleanUrl.searchParams.delete('agent');
|
|
487
|
-
_cleanUrl.searchParams.delete('a');
|
|
488
|
-
_cleanUrl.searchParams.delete('session');
|
|
489
|
-
if (urlAgent && !urlAid) {
|
|
490
|
-
// 如果没有 aid 但有旧格式 agent,添加 aid
|
|
491
|
-
var _agentObj = findAgentByPath(urlAgent);
|
|
492
|
-
if (_agentObj && _agentObj.aid) _cleanUrl.searchParams.set('aid', _agentObj.aid);
|
|
493
|
-
}
|
|
494
|
-
window.history.replaceState({}, '', _cleanUrl.toString());
|
|
495
|
-
} catch (_) {}
|
|
496
473
|
|
|
497
474
|
if (isPopout) {
|
|
498
475
|
const agentObj = findAgentByPath(urlAgent);
|
|
@@ -520,12 +497,12 @@ async function initChat() {
|
|
|
520
497
|
}
|
|
521
498
|
|
|
522
499
|
// 如果 URL 中有 ?g= 纯数字 session ID,优先恢复群聊
|
|
523
|
-
if (
|
|
500
|
+
if (urlGroupSession && /^[0-9]+$/.test(urlGroupSession)) {
|
|
524
501
|
if (urlAgent && urlAgent !== state.activeAgent) {
|
|
525
502
|
state.activeAgent = urlAgent;
|
|
526
503
|
StatePersistence.save('activeAgent', urlAgent);
|
|
527
504
|
}
|
|
528
|
-
_restoreGroupBySession(
|
|
505
|
+
_restoreGroupBySession(urlGroupSession);
|
|
529
506
|
} else if (urlAgent) {
|
|
530
507
|
var resolved = urlAgent;
|
|
531
508
|
if (!findAgentByPath(resolved)) {
|
|
@@ -536,17 +513,8 @@ async function initChat() {
|
|
|
536
513
|
selectAgent(resolved);
|
|
537
514
|
}
|
|
538
515
|
} else if (urlSession) {
|
|
539
|
-
// 只有 session 没有 agent
|
|
540
|
-
var
|
|
541
|
-
if (urlSession.indexOf('_web_') >= 0) {
|
|
542
|
-
targetAgent = urlSession.split('_web_')[0] || findMasterAgentPath();
|
|
543
|
-
}
|
|
544
|
-
// 新格式 sess_xxx 无法推断 agent,回退 master
|
|
545
|
-
var target = targetAgent;
|
|
546
|
-
if (!findAgentByPath(target)) {
|
|
547
|
-
console.warn('Session-inferred agent not found, fallback to master:', target);
|
|
548
|
-
target = findMasterAgentPath();
|
|
549
|
-
}
|
|
516
|
+
// 只有 session 没有 agent,回退 master agent
|
|
517
|
+
var target = findMasterAgentPath();
|
|
550
518
|
if (target !== state.activeAgent) {
|
|
551
519
|
selectAgent(target);
|
|
552
520
|
}
|
|
@@ -1822,26 +1790,17 @@ function findAgentByPath(path) {
|
|
|
1822
1790
|
return state.agentsFlat.find(function(a) { return a.path === path; });
|
|
1823
1791
|
}
|
|
1824
1792
|
|
|
1825
|
-
// [v1.32.
|
|
1793
|
+
// [v1.32.7] 查找系统级 Agent 的路径
|
|
1826
1794
|
function findMasterAgentPath() {
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|| state.agentsFlat.find(function(x) { return x.path === 'default'; })
|
|
1830
|
-
|| state.agentsFlat.find(function(x) { return x.system && x.name === '全权Agent'; })
|
|
1831
|
-
|| state.agentsFlat.find(function(x) { return x.system; });
|
|
1832
|
-
return a ? a.path : 'default';
|
|
1795
|
+
var a = state.agentsFlat.find(function(x) { return x.path === '1'; });
|
|
1796
|
+
return a ? a.path : '1';
|
|
1833
1797
|
}
|
|
1834
1798
|
function findHelperAgentPath() {
|
|
1835
|
-
var a = state.agentsFlat.find(function(x) { return x.path === '2'; })
|
|
1836
|
-
|| state.agentsFlat.find(function(x) { return x.path === '配置助手'; })
|
|
1837
|
-
|| state.agentsFlat.find(function(x) { return x.system && x.name === '配置助手'; })
|
|
1838
|
-
|| null;
|
|
1799
|
+
var a = state.agentsFlat.find(function(x) { return x.path === '2'; });
|
|
1839
1800
|
return a ? a.path : null;
|
|
1840
1801
|
}
|
|
1841
1802
|
function isSystemAgentPath(path) {
|
|
1842
|
-
|
|
1843
|
-
var hp = findHelperAgentPath();
|
|
1844
|
-
return path === mp || (hp !== null && path === hp);
|
|
1803
|
+
return path === '1' || path === '2';
|
|
1845
1804
|
}
|
|
1846
1805
|
|
|
1847
1806
|
function getActiveAgentObj() {
|
|
@@ -1854,8 +1813,7 @@ async function loadAgents() {
|
|
|
1854
1813
|
state.agentTree = treeData || [];
|
|
1855
1814
|
state.agentsFlat = flattenTree(state.agentTree, 0, null);
|
|
1856
1815
|
|
|
1857
|
-
//
|
|
1858
|
-
// 而是依赖 findMasterAgentPath() 来正确解析 master agent 路径
|
|
1816
|
+
// 使用 findMasterAgentPath() 解析 master agent 路径
|
|
1859
1817
|
var _masterPath = findMasterAgentPath();
|
|
1860
1818
|
|
|
1861
1819
|
for (var i = 0; i < state.agentsFlat.length; i++) {
|
|
@@ -1929,7 +1887,7 @@ function renderRightPanelSections() {
|
|
|
1929
1887
|
function renderMasterAgentCard() {
|
|
1930
1888
|
var el = document.getElementById('rpMasterAgent');
|
|
1931
1889
|
if (!el) return;
|
|
1932
|
-
//
|
|
1890
|
+
// 使用 findMasterAgentPath() 获取 master agent 路径
|
|
1933
1891
|
var masterPath = findMasterAgentPath();
|
|
1934
1892
|
var agent = findAgentByPath(masterPath);
|
|
1935
1893
|
var isActive = state.activeAgent === masterPath;
|
|
@@ -1953,7 +1911,7 @@ function renderMasterAgentCard() {
|
|
|
1953
1911
|
function renderHelperAgentCard() {
|
|
1954
1912
|
var el = document.getElementById('rpHelperAgent');
|
|
1955
1913
|
if (!el) return;
|
|
1956
|
-
//
|
|
1914
|
+
// 使用 findHelperAgentPath() 获取 helper agent 路径
|
|
1957
1915
|
var helperPath = findHelperAgentPath();
|
|
1958
1916
|
if (!helperPath) { el.innerHTML = ''; return; } // 无配置助手则不渲染
|
|
1959
1917
|
var agent = findAgentByPath(helperPath);
|
|
@@ -2678,40 +2636,18 @@ async function loadSessions() {
|
|
|
2678
2636
|
// 优先级: URL session 参数 > localStorage 持久化的 session > 最新 session
|
|
2679
2637
|
// [fix] 所有候选 session ID 必须属于当前 agent 的会话列表,防止错乱到其它 agent 的历史对话
|
|
2680
2638
|
const urlParams = new URLSearchParams(window.location.search);
|
|
2681
|
-
const urlSession = UrlCodec.decode(urlParams.get('s') || '')
|
|
2639
|
+
const urlSession = UrlCodec.decode(urlParams.get('s') || '');
|
|
2682
2640
|
var targetSessionId = null;
|
|
2683
2641
|
|
|
2684
2642
|
if (urlSession && state.sessions.some(s => s.id === urlSession)) {
|
|
2685
2643
|
// URL 指定了有效的 session ID,直接选中(刷新恢复)
|
|
2686
2644
|
targetSessionId = urlSession;
|
|
2687
|
-
} else if (urlSession) {
|
|
2688
|
-
// [v1.23.24] 前缀匹配 fallback:前端生成的临时 ID 与后端 canonical ID 可能不同
|
|
2689
|
-
// 例如前端 "default_web_20250101120000" 后端实际为 "default_web_20250101120000_a1b2c3"
|
|
2690
|
-
var prefixMatch = state.sessions.find(function(s) {
|
|
2691
|
-
return s.id.startsWith(urlSession) || urlSession.startsWith(s.id);
|
|
2692
|
-
});
|
|
2693
|
-
if (prefixMatch) {
|
|
2694
|
-
targetSessionId = prefixMatch.id;
|
|
2695
|
-
// 更新 URL 为 canonical ID,避免下次刷新再走 fallback
|
|
2696
|
-
try {
|
|
2697
|
-
var _fixUrl = new URL(window.location.href);
|
|
2698
|
-
_fixUrl.searchParams.set('s', UrlCodec.encode(prefixMatch.id));
|
|
2699
|
-
window.history.replaceState({}, '', _fixUrl.toString());
|
|
2700
|
-
} catch (_) {}
|
|
2701
|
-
}
|
|
2702
2645
|
}
|
|
2703
2646
|
if (!targetSessionId && state._pendingSessionRestore && state.sessions.some(s => s.id === state._pendingSessionRestore)) {
|
|
2704
2647
|
// 从 localStorage 恢复的 session(beforeunload 触发的保存)
|
|
2705
2648
|
targetSessionId = state._pendingSessionRestore;
|
|
2706
2649
|
state._pendingSessionRestore = null; // 清除,防止重复恢复
|
|
2707
2650
|
} else if (!targetSessionId && state._pendingSessionRestore) {
|
|
2708
|
-
// [v1.23.24] localStorage 恢复的 ID 也不匹配,尝试前缀匹配
|
|
2709
|
-
var lsPrefixMatch = state.sessions.find(function(s) {
|
|
2710
|
-
return s.id.startsWith(state._pendingSessionRestore) || state._pendingSessionRestore.startsWith(s.id);
|
|
2711
|
-
});
|
|
2712
|
-
if (lsPrefixMatch) {
|
|
2713
|
-
targetSessionId = lsPrefixMatch.id;
|
|
2714
|
-
}
|
|
2715
2651
|
state._pendingSessionRestore = null;
|
|
2716
2652
|
}
|
|
2717
2653
|
if (!targetSessionId && !state.activeSessionId && state.sessions.length > 0) {
|
|
@@ -3039,10 +2975,6 @@ async function selectSession(id) {
|
|
|
3039
2975
|
try {
|
|
3040
2976
|
const url = new URL(window.location.href);
|
|
3041
2977
|
url.searchParams.set('s', UrlCodec.encode(id));
|
|
3042
|
-
// 移除旧格式参数
|
|
3043
|
-
url.searchParams.delete('a');
|
|
3044
|
-
url.searchParams.delete('agent');
|
|
3045
|
-
url.searchParams.delete('session');
|
|
3046
2978
|
// 设置 aid(数字 agent ID)
|
|
3047
2979
|
var _selAgentObj = findAgentByPath(state.activeAgent);
|
|
3048
2980
|
if (_selAgentObj && _selAgentObj.aid) {
|
|
@@ -2502,7 +2502,7 @@ async function handleInjectChoice(choice) {
|
|
|
2502
2502
|
clearDraft();
|
|
2503
2503
|
|
|
2504
2504
|
try {
|
|
2505
|
-
const rawSid = state.activeSessionId
|
|
2505
|
+
const rawSid = state.activeSessionId || 'web_default';
|
|
2506
2506
|
const resp = await fetch('/api/chat/inject', {
|
|
2507
2507
|
method: 'POST',
|
|
2508
2508
|
headers: { 'Content-Type': 'application/json' },
|
package/web/ui/chat/groupchat.js
CHANGED
|
@@ -255,8 +255,9 @@ async function selectGroup(gid) {
|
|
|
255
255
|
var sessionId = sessionData.sid;
|
|
256
256
|
// 用群聊专用 ?g= 参数更新 URL(不刷新页面),纯数字 session ID
|
|
257
257
|
var newUrl = '/ui/chat/chat_container.html?g=' + sessionId;
|
|
258
|
-
|
|
259
|
-
|
|
258
|
+
var _grpAgentObj = (typeof findAgentByPath === 'function') ? findAgentByPath(state.activeAgent) : null;
|
|
259
|
+
if (_grpAgentObj && _grpAgentObj.aid) {
|
|
260
|
+
newUrl += '&aid=' + _grpAgentObj.aid;
|
|
260
261
|
}
|
|
261
262
|
window.history.replaceState({groupSession: sessionId, groupId: gid}, '', newUrl);
|
|
262
263
|
}
|
|
@@ -344,13 +345,14 @@ function exitGroupChat() {
|
|
|
344
345
|
currentView = 'chat';
|
|
345
346
|
currentGroupId = null;
|
|
346
347
|
groupMessages = [];
|
|
347
|
-
//
|
|
348
|
+
// 清除群聊 ?g= session URL,恢复普通聊天 URL(统一使用 aid 数字 ID)
|
|
348
349
|
var cleanUrl = '/ui/chat/chat_container.html';
|
|
349
|
-
|
|
350
|
-
|
|
350
|
+
var _exitAgentObj = (typeof findAgentByPath === 'function') ? findAgentByPath(state.activeAgent) : null;
|
|
351
|
+
if (_exitAgentObj && _exitAgentObj.aid) {
|
|
352
|
+
cleanUrl += '?aid=' + _exitAgentObj.aid;
|
|
351
353
|
}
|
|
352
354
|
if (typeof state !== 'undefined' && state.activeSessionId && state.activeSessionId !== '__new__') {
|
|
353
|
-
cleanUrl += (cleanUrl.indexOf('?') >= 0 ? '&' : '?') + 's=' +
|
|
355
|
+
cleanUrl += (cleanUrl.indexOf('?') >= 0 ? '&' : '?') + 's=' + UrlCodec.encode(state.activeSessionId);
|
|
354
356
|
}
|
|
355
357
|
window.history.replaceState({}, '', cleanUrl);
|
|
356
358
|
// 清除群聊 localStorage 持久化状态
|
|
@@ -456,8 +458,9 @@ function startPrivateChatFromGroup(agentPath) {
|
|
|
456
458
|
StatePersistence.remove('currentGroupId');
|
|
457
459
|
// 清除群聊 URL 中的 ?g= 参数
|
|
458
460
|
var cleanUrl = '/ui/chat/chat_container.html';
|
|
459
|
-
|
|
460
|
-
|
|
461
|
+
var _memAgentObj = (typeof findAgentByPath === 'function') ? findAgentByPath(agentPath) : null;
|
|
462
|
+
if (_memAgentObj && _memAgentObj.aid) {
|
|
463
|
+
cleanUrl += '?aid=' + _memAgentObj.aid;
|
|
461
464
|
}
|
|
462
465
|
window.history.replaceState({}, '', cleanUrl);
|
|
463
466
|
// 让 selectAgent 处理完整的私聊切换
|