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 = "default"
39
- agent_id: int = 0 # 所属agent ID(数字ID,从1开始,0表示未分配)
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", 0) or 0),
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
- return 0
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.32.7",
3
+ "version": "1.32.8",
4
4
  "description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
5
5
  "main": "main.py",
6
6
  "bin": {
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 0
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) if agent else 0
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
- MAX(CASE WHEN agent_id != ? THEN agent_id ELSE NULL END) as raw_agent_id FROM memories
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, target_aid)).fetchall()
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"MAX(CASE WHEN agent_id > 0 THEN agent_id ELSE NULL END) as raw_agent_id FROM memories "
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": (int(raw_aid) if raw_aid is not None else 0), # 数字 ID 供 URL 使用
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", 0)
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
- window.location.href='/ui/chat/chat_container.html?mode=exec&a='+UrlCodec.encode(path);
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
- // [v1.23.81] 返回聊天:通过纯数字 session ID 恢复群聊(不再传递 group_id)
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 agent=params.get('from_agent');
166
+ // 从 URL 参数中恢复聊天状态(统一使用 aid 数字 ID)
167
+ var aid=params.get('from_aid');
168
168
  var session=params.get('from_session');
169
- // [v1.23.81] 群聊纯数字 session ID(优先级最高,覆盖 ?s= 个人会话参数)
170
- var groupSession=params.get('from_group_session');
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(agent)parts.push('a='+encodeURIComponent(agent));
176
+ if(aid)parts.push('aid='+aid);
177
177
  if(mode)parts.push('mode='+encodeURIComponent(mode));
178
178
  } else {
179
179
  // 个人聊天模式
180
- if(agent)parts.push('a='+encodeURIComponent(agent));
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
  }
@@ -86,19 +86,20 @@ function closeMobileAgentPanel() {
86
86
  if (overlay) overlay.classList.remove('active');
87
87
  }
88
88
 
89
- // [v1.23.81] 跳转后台管理:携带当前聊天上下文(agent、session、群聊session ID),以便"返回聊天"正确恢复
89
+ // 跳转后台管理:携带当前聊天上下文(aid数字ID、session、群聊ID),以便"返回聊天"正确恢复
90
90
  function goToAdmin() {
91
91
  var params = new URLSearchParams();
92
92
  var page = 'dashboard';
93
- // 传递当前聊天状态,供"返回聊天"恢复
94
- if (state.activeAgent) params.set('from_agent', state.activeAgent);
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
- // [v1.23.81] 传递群聊纯数字 session ID(从 URL 读取),而非 JS 变量
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('from_group_session', gSession);
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
- // [v1.23.81] 不再从 localStorage 恢复群聊状态(统一由 URL ?g= 参数恢复)
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') || '') || UrlCodec.decode(urlParams.get('session') || '');
380
+ const urlSession = UrlCodec.decode(urlParams.get('s') || '');
386
381
  const isPopout = urlParams.get('popout') === '1';
387
- // [v1.23.81] 群聊纯数字 session ID(?g= 参数,优先级最高)
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: 优先 aid(数字),兼容 a/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 (_effectiveGroupSession && /^[0-9]+$/.test(_effectiveGroupSession)) {
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(_effectiveGroupSession);
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') || '') || UrlCodec.decode(urlParams.get('session') || '');
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 ? state.activeSessionId.replace(`${state.activeAgent}_`, '') : 'web_default';
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' },
@@ -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
- if (typeof state !== 'undefined' && state.activeAgent) {
259
- newUrl += '&a=' + encodeURIComponent(state.activeAgent);
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
- // [v1.23.81] 清除群聊 ?g= session URL,恢复普通聊天 URL
348
+ // 清除群聊 ?g= session URL,恢复普通聊天 URL(统一使用 aid 数字 ID)
348
349
  var cleanUrl = '/ui/chat/chat_container.html';
349
- if (typeof state !== 'undefined' && state.activeAgent && state.activeAgent !== (typeof findMasterAgentPath === 'function' ? findMasterAgentPath() : '1')) {
350
- cleanUrl += '?a=' + encodeURIComponent(state.activeAgent);
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=' + encodeURIComponent(state.activeSessionId);
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
- if (typeof state !== 'undefined' && agentPath && agentPath !== (typeof findMasterAgentPath === 'function' ? findMasterAgentPath() : '1')) {
460
- cleanUrl += '?a=' + encodeURIComponent(agentPath);
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 处理完整的私聊切换