myagent-ai 1.32.7 → 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/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"],
|
|
@@ -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"""
|
package/package.json
CHANGED
package/web/api_server.py
CHANGED
|
@@ -2189,7 +2189,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
2189
2189
|
"""后台任务:即使 SSE 断开也完整执行并保存结果"""
|
|
2190
2190
|
logger.info(f"[{session_id}] _run_stream_task 开始执行")
|
|
2191
2191
|
# [v1.32.2] 安全修复: 定义 agent_id,避免 except 块中引用时 NameError
|
|
2192
|
-
_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
|
|
2193
2193
|
try:
|
|
2194
2194
|
agent_cfg = self._read_agent_config(agent_path)
|
|
2195
2195
|
model_chain = self._build_model_chain(agent_cfg, agent_path)
|
|
@@ -4327,21 +4327,21 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4327
4327
|
# 只统计用户可见的消息数(排除 llm_output 和 conversation_insight)
|
|
4328
4328
|
if agent:
|
|
4329
4329
|
# 将 agent 路径转为数字 ID,精确过滤
|
|
4330
|
-
target_aid = self.core.memory.get_agent_id(agent)
|
|
4331
|
-
# 统一使用 agent_id
|
|
4330
|
+
target_aid = self.core.memory.get_agent_id(agent)
|
|
4331
|
+
# 统一使用 agent_id 精确匹配
|
|
4332
4332
|
rows = conn.execute(
|
|
4333
4333
|
f"""SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last,
|
|
4334
|
-
|
|
4334
|
+
agent_id as raw_agent_id FROM memories
|
|
4335
4335
|
WHERE category = 'session' AND role != ''
|
|
4336
4336
|
AND key NOT IN {_hidden}
|
|
4337
4337
|
AND agent_id = ?
|
|
4338
4338
|
GROUP BY session_id ORDER BY last DESC LIMIT 100""",
|
|
4339
|
-
(target_aid,
|
|
4339
|
+
(target_aid,)).fetchall()
|
|
4340
4340
|
else:
|
|
4341
4341
|
# [v1.27.2] 无 agent 过滤时也返回 agent_id,供后台管理页面使用
|
|
4342
4342
|
rows = conn.execute(
|
|
4343
4343
|
f"SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last, "
|
|
4344
|
-
f"
|
|
4344
|
+
f"agent_id as raw_agent_id FROM memories "
|
|
4345
4345
|
f"WHERE category = 'session' AND role != '' "
|
|
4346
4346
|
f"AND key NOT IN {_hidden} "
|
|
4347
4347
|
f"GROUP BY session_id ORDER BY last DESC LIMIT 100").fetchall()
|
|
@@ -4354,7 +4354,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
4354
4354
|
agent_name = _agent_id_map.get(int(raw_aid), "")
|
|
4355
4355
|
sessions.append({"id": r["session_id"], "messages": r["cnt"], "last": r["last"],
|
|
4356
4356
|
"agent_id": agent_name, # 返回 agent 名称(非数字 ID)
|
|
4357
|
-
"agent_db_id":
|
|
4357
|
+
"agent_db_id": int(raw_aid), # 数字 ID 供 URL 使用
|
|
4358
4358
|
"display_name": "", "preview": ""})
|
|
4359
4359
|
# 批量获取自定义会话名称
|
|
4360
4360
|
sids = [s["id"] for s in sessions]
|
|
@@ -6363,7 +6363,7 @@ window.addEventListener('beforeunload', function() {{
|
|
|
6363
6363
|
recent = agent.memory.get_conversation(session_id, limit=3)
|
|
6364
6364
|
_has_assistant = any(e.role == "assistant" for e in recent)
|
|
6365
6365
|
if not _has_assistant and final_response and final_response.strip():
|
|
6366
|
-
_fallback_agent_id = context.metadata.get("agent_db_id",
|
|
6366
|
+
_fallback_agent_id = context.metadata.get("agent_db_id", 1)
|
|
6367
6367
|
agent.memory.add_session(agent_id=_fallback_agent_id,
|
|
6368
6368
|
session_id=session_id, role="assistant", content=final_response,
|
|
6369
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)) {
|
|
@@ -2659,7 +2636,7 @@ async function loadSessions() {
|
|
|
2659
2636
|
// 优先级: URL session 参数 > localStorage 持久化的 session > 最新 session
|
|
2660
2637
|
// [fix] 所有候选 session ID 必须属于当前 agent 的会话列表,防止错乱到其它 agent 的历史对话
|
|
2661
2638
|
const urlParams = new URLSearchParams(window.location.search);
|
|
2662
|
-
const urlSession = UrlCodec.decode(urlParams.get('s') || '')
|
|
2639
|
+
const urlSession = UrlCodec.decode(urlParams.get('s') || '');
|
|
2663
2640
|
var targetSessionId = null;
|
|
2664
2641
|
|
|
2665
2642
|
if (urlSession && state.sessions.some(s => s.id === urlSession)) {
|
|
@@ -2998,10 +2975,6 @@ async function selectSession(id) {
|
|
|
2998
2975
|
try {
|
|
2999
2976
|
const url = new URL(window.location.href);
|
|
3000
2977
|
url.searchParams.set('s', UrlCodec.encode(id));
|
|
3001
|
-
// 移除旧格式参数
|
|
3002
|
-
url.searchParams.delete('a');
|
|
3003
|
-
url.searchParams.delete('agent');
|
|
3004
|
-
url.searchParams.delete('session');
|
|
3005
2978
|
// 设置 aid(数字 agent ID)
|
|
3006
2979
|
var _selAgentObj = findAgentByPath(state.activeAgent);
|
|
3007
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 处理完整的私聊切换
|