myagent-ai 1.32.2 → 1.32.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.32.2",
3
+ "version": "1.32.4",
4
4
  "description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
5
5
  "main": "main.py",
6
6
  "bin": {
@@ -2136,10 +2136,16 @@ async function loadAllAgentSessions() {
2136
2136
  // 快速对话: 选中 agent + 切换执行模式 + 新建会话
2137
2137
  function quickChatAgent(agentPath) {
2138
2138
  // 选中 agent
2139
+ var _qPrevAgent = state.activeAgent;
2139
2140
  state.activeAgent = agentPath;
2140
2141
  StatePersistence.save('activeAgent', agentPath);
2141
2142
  state.activeSessionId = null;
2142
2143
  state.messages = [];
2144
+ // [fix] 切换到不同 agent 时,清除旧 agent 的待恢复会话 ID
2145
+ if (_qPrevAgent !== agentPath) {
2146
+ state._pendingSessionRestore = null;
2147
+ }
2148
+ // [fix] 不再清除 URL ?s= 参数,由 loadSessions 中校验 session 归属来防止错乱
2143
2149
  // 展开所有父节点
2144
2150
  var parts = agentPath.split('/');
2145
2151
  var cumPath = '';
@@ -2188,10 +2194,21 @@ async function selectAgent(agentPath) {
2188
2194
  // 移动端:立即关闭右侧栏,不要等异步操作完成
2189
2195
  if (isMobile()) closeMobileAgentPanel();
2190
2196
  // Always reload sessions even if clicking the same agent
2197
+ var _prevAgent = state.activeAgent;
2191
2198
  state.activeAgent = agentPath;
2192
2199
  StatePersistence.save('activeAgent', agentPath);
2193
2200
  state.activeSessionId = null;
2194
2201
  state.messages = [];
2202
+ // [fix] 切换到不同 agent 时,清除旧 agent 的待恢复会话 ID,防止 loadSessions 选中旧 agent 的会话
2203
+ // 注意:仅在 agent 确实发生变化时才清除,避免影响 initChat 中同 agent 的会话恢复逻辑
2204
+ if (_prevAgent !== agentPath) {
2205
+ state._pendingSessionRestore = null;
2206
+ }
2207
+ // [fix] 注意:不再在此处清除 URL 中的 ?s= 参数!
2208
+ // 原因:initChat 恢复场景中,URL 可能同时包含 ?aid=B&s=sess_b1,
2209
+ // 如果在此处删除 s 参数,loadSessions 将无法恢复指定 session。
2210
+ // 正确的做法是在 loadSessions 中校验 URL session 是否属于当前 agent,
2211
+ // 如果不属于则忽略(不选中),从而避免错乱。
2195
2212
  // 递增序号,使任何进行中的 selectSession 请求失效
2196
2213
  state._sessionLoadSeq++;
2197
2214
  var parts = agentPath.split('/');
@@ -2220,16 +2237,12 @@ async function selectAgent(agentPath) {
2220
2237
  await loadSessions();
2221
2238
 
2222
2239
  // loadSessions 内部会 auto-select 最新 session;
2223
- // 如果没有 session,则保持 "新对话" 空窗状态
2240
+ // 如果没有 session,则进入"新对话"状态
2224
2241
  // [v1.18.9] 如果 loadSessions 已成功选中了 session,不要覆盖其标题
2225
2242
  if (!state.activeSessionId || state.activeSessionId === '__new__') {
2226
- state._selectedSessionLabel = null;
2227
- var selAgent = findAgentByPath(agentPath);
2228
- var agentLabel = selAgent ? (selAgent.avatar_emoji + ' ' + selAgent.name) : agentPath;
2229
- document.getElementById('headerTitle').textContent = '新对话';
2230
- var details = await loadAgentDetails(agentPath);
2231
- updateWelcomeCard(agentPath, details);
2232
- renderMessages();
2243
+ // [fix] 对于没有历史会话的 agent,直接进入新对话状态
2244
+ // 确保 activeSessionId 被设为 '__new__',左侧栏同步显示空列表
2245
+ newChat();
2233
2246
  }
2234
2247
  // 如果 loadSessions 已经 auto-selected 了 session,UI 已由 selectSession 设置好,不再覆盖
2235
2248
 
@@ -2592,9 +2605,25 @@ async function loadSessions() {
2592
2605
 
2593
2606
  // 创建新的 Promise 并缓存
2594
2607
  const loadPromise = (async () => {
2608
+ // [fix] 在闭包入口捕获当前 agent,防止 await 后 state.activeAgent 被其它 selectAgent 改变
2609
+ // 导致 agent B 的 sessions 被错误地写入 state.agentSessions['C']
2610
+ const loadAgent = currentAgent;
2595
2611
  try {
2596
- const url = `/api/sessions?agent=${encodeURIComponent(state.activeAgent)}`;
2612
+ const url = `/api/sessions?agent=${encodeURIComponent(loadAgent)}`;
2597
2613
  const data = await api(url);
2614
+ // [fix] 竞态保护:如果 await 期间 agent 已切换,不更新 state.sessions(避免覆盖新 agent 的数据)
2615
+ if (state.activeAgent !== loadAgent) {
2616
+ // 仅更新缓存,不动 state.sessions
2617
+ const sessions = (data || []).map(s => ({
2618
+ id: s.id,
2619
+ name: s.display_name || formatSessionName(s.id),
2620
+ messages: s.messages || 0,
2621
+ last: s.last || '',
2622
+ preview: s.preview || '',
2623
+ }));
2624
+ state.agentSessions[loadAgent] = sessions;
2625
+ return { sessions: [], selectedId: null, stale: true };
2626
+ }
2598
2627
  state.sessions = (data || []).map(s => ({
2599
2628
  id: s.id,
2600
2629
  name: s.display_name || formatSessionName(s.id),
@@ -2602,11 +2631,18 @@ async function loadSessions() {
2602
2631
  last: s.last || '',
2603
2632
  preview: s.preview || '',
2604
2633
  }));
2605
- // Cache per agent
2606
- state.agentSessions[state.activeAgent] = [...state.sessions];
2634
+ // Cache per agent — 使用闭包捕获的 loadAgent 而非 state.activeAgent
2635
+ state.agentSessions[loadAgent] = [...state.sessions];
2607
2636
  } catch (e) {
2608
- // Offline - try cache
2609
- state.sessions = state.agentSessions[state.activeAgent] || [];
2637
+ // Offline - try cache — 使用 loadAgent
2638
+ if (state.activeAgent === loadAgent) {
2639
+ state.sessions = state.agentSessions[loadAgent] || [];
2640
+ }
2641
+ }
2642
+
2643
+ // [fix] 竞态保护:如果 agent 已切换,不渲染 UI、不选中 session
2644
+ if (state.activeAgent !== loadAgent) {
2645
+ return { sessions: [], selectedId: null, stale: true };
2610
2646
  }
2611
2647
 
2612
2648
  // Always update session list UI
@@ -2615,6 +2651,7 @@ async function loadSessions() {
2615
2651
 
2616
2652
  // Auto-select most recent session if none selected
2617
2653
  // 优先级: URL session 参数 > localStorage 持久化的 session > 最新 session
2654
+ // [fix] 所有候选 session ID 必须属于当前 agent 的会话列表,防止错乱到其它 agent 的历史对话
2618
2655
  const urlParams = new URLSearchParams(window.location.search);
2619
2656
  const urlSession = UrlCodec.decode(urlParams.get('s') || '') || UrlCodec.decode(urlParams.get('session') || '');
2620
2657
  var targetSessionId = null;
@@ -2656,16 +2693,10 @@ async function loadSessions() {
2656
2693
  // 默认选中最新 session
2657
2694
  targetSessionId = state.sessions[0].id;
2658
2695
  }
2659
- // [v1.24.1] 强制恢复:如果 URL localStorage 有 session ID,但不在 session 列表中
2660
- // (可能因为 sess_xxx 格式的新会话未匹配到旧格式 LIKE 查询),仍然尝试直接加载
2661
- if (!targetSessionId) {
2662
- var fallbackSession = urlSession || state._pendingSessionRestore;
2663
- if (fallbackSession && fallbackSession !== '__new__') {
2664
- targetSessionId = fallbackSession;
2665
- state._pendingSessionRestore = null;
2666
- console.log('[loadSessions] Session not in list, force restoring:', targetSessionId);
2667
- }
2668
- }
2696
+ // [fix] 移除 v1.24.1 的强制恢复逻辑:不再强制加载不属于当前 agent session ID
2697
+ // 旧逻辑会在 URL/localStorage 残留旧 agent 的 session ID 时,强制加载该会话,
2698
+ // 导致点击新 agent 头像后错乱显示旧 agent 的历史对话。
2699
+ // 对于当前 agent 确实没有匹配 session 的情况,应该进入"新对话"状态,而非加载其它 agent 的会话。
2669
2700
 
2670
2701
  if (targetSessionId) {
2671
2702
  await selectSession(targetSessionId);