myagent-ai 1.15.48 → 1.15.50

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.
@@ -749,8 +749,8 @@ class UpdateManager:
749
749
  pkg_data = json.loads((PROJECT_ROOT / "package.json").read_text(encoding="utf-8"))
750
750
  pkg_name = pkg_data.get("name", "myagent-ai")
751
751
 
752
- # 构建 npm install 命令
753
- npm_cmd = ["npm", "install", "-g", pkg_name]
752
+ # 构建 npm install 命令 — 使用 @latest 确保拉取最新版本,避免缓存
753
+ npm_cmd = ["npm", "install", "-g", f"{pkg_name}@latest"]
754
754
  if registry != "https://registry.npmjs.org":
755
755
  npm_cmd.extend(["--registry", registry])
756
756
  logger.info(f"使用 npm 镜像: {registry}")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.15.48",
3
+ "version": "1.15.50",
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
@@ -279,7 +279,9 @@ class ApiServer:
279
279
  # ── 会话管理 ──
280
280
  r.add_get("/api/sessions", self.handle_list_sessions)
281
281
  r.add_get("/api/sessions/{sid}/messages", self.handle_get_messages)
282
+ r.add_get("/api/sessions/{sid}/raw", self.handle_get_raw_messages)
282
283
  r.add_get("/api/session/messages", self.handle_get_messages_query) # query param version (supports / in sid)
284
+ r.add_get("/api/session/raw", self.handle_get_raw_messages_query) # query param version for raw
283
285
  r.add_delete("/api/sessions/{sid}", self.handle_delete_session)
284
286
  r.add_delete("/api/session", self.handle_delete_session_query) # query param version
285
287
  r.add_delete("/api/sessions/{sid}/messages", self.handle_clear_session_messages)
@@ -2570,6 +2572,36 @@ class ApiServer:
2570
2572
  entries = [e for e in entries if (e.key or "") not in self._HIDDEN_KEYS]
2571
2573
  return web.json_response([{"role": e.role, "content": e.content, "time": e.created_at, "key": e.key or ""} for e in entries])
2572
2574
 
2575
+ async def handle_get_raw_messages(self, request):
2576
+ """GET /api/sessions/{sid}/raw - 获取会话全部原始消息(含 llm_output 等)"""
2577
+ sid = request.match_info["sid"]
2578
+ if not self.core.memory:
2579
+ return web.json_response([])
2580
+ limit = min(int(request.query.get("limit", 5000)), 5000)
2581
+ offset = int(request.query.get("offset", 0))
2582
+ entries = self.core.memory.get_conversation_all(sid, limit=limit + offset)
2583
+ entries = entries[offset:]
2584
+ return web.json_response([{
2585
+ "role": e.role, "content": e.content, "time": e.created_at,
2586
+ "key": e.key or "", "id": e.id,
2587
+ } for e in entries])
2588
+
2589
+ async def handle_get_raw_messages_query(self, request):
2590
+ """GET /api/session/raw?sid=... - 通过 query 参数获取原始消息(支持 session_id 中包含 /)"""
2591
+ sid = request.query.get("sid", "")
2592
+ if not sid:
2593
+ return web.json_response([])
2594
+ if not self.core.memory:
2595
+ return web.json_response([])
2596
+ limit = min(int(request.query.get("limit", 5000)), 5000)
2597
+ offset = int(request.query.get("offset", 0))
2598
+ entries = self.core.memory.get_conversation_all(sid, limit=limit + offset)
2599
+ entries = entries[offset:]
2600
+ return web.json_response([{
2601
+ "role": e.role, "content": e.content, "time": e.created_at,
2602
+ "key": e.key or "", "id": e.id,
2603
+ } for e in entries])
2604
+
2573
2605
  async def handle_get_messages_query(self, request):
2574
2606
  """GET /api/session/messages?sid=... - 通过 query 参数获取会话消息(支持 session_id 中包含 /)"""
2575
2607
  sid = request.query.get("sid", "")
@@ -181,6 +181,7 @@ input,textarea,select{font:inherit}
181
181
  .sidebar-footer{
182
182
  padding:12px 16px;border-top:1px solid var(--border-light);
183
183
  display:flex;flex-direction:column;gap:6px;
184
+ flex-shrink:0;
184
185
  }
185
186
  .sidebar-footer-btn{
186
187
  display:flex;align-items:center;gap:10px;padding:8px 12px;
@@ -2098,7 +2099,7 @@ body.popout-mode #popoutBtn{display:none !important}
2098
2099
  .sidebar.collapsed .sidebar-search{flex-direction:column}
2099
2100
  .sidebar.collapsed .session-list{flex-direction:column}
2100
2101
  .sidebar.collapsed .sidebar-footer{flex-direction:column}
2101
- .sidebar-footer{padding-bottom:max(12px, env(safe-area-inset-bottom))}
2102
+ .sidebar-footer{padding-bottom:max(16px, calc(env(safe-area-inset-bottom) + 8px))}
2102
2103
 
2103
2104
  /* ── Header ── */
2104
2105
  .main-header{
package/web/ui/index.html CHANGED
@@ -38,7 +38,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;b
38
38
  .sidebar{width:220px;background:var(--surface);border-right:1px solid var(--border);display:flex;flex-direction:column;flex-shrink:0}
39
39
  .sidebar .logo{padding:20px;font-size:18px;font-weight:700;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px}
40
40
  .sidebar .logo span{color:var(--primary)}
41
- .nav{flex:1;padding:8px;overflow-y:auto}
41
+ .nav{flex:1;padding:8px;overflow-y:auto;min-height:0}
42
42
  .nav-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:var(--radius);cursor:pointer;color:var(--text2);font-size:14px;transition:all .15s;margin-bottom:2px}
43
43
  .nav-item:hover{background:var(--surface2);color:var(--text)}
44
44
  .nav-item.active{background:var(--primary);color:#fff}
@@ -180,6 +180,7 @@ tr:hover{background:var(--surface2)}
180
180
  .sidebar.mobile-open .logo .logo-text{display:inline!important}
181
181
  .sidebar.mobile-open.collapsed .nav-item{justify-content:flex-start;padding:8px 12px}
182
182
  .sidebar.mobile-open.collapsed .logo{justify-content:flex-start;padding:16px 12px}
183
+ .sidebar-footer-text{padding-bottom:max(12px, calc(env(safe-area-inset-bottom) + 8px))}
183
184
  .mobile-overlay{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:45;display:none}
184
185
  .mobile-overlay.active{display:block}
185
186
  .header{padding:12px 16px}
@@ -216,6 +217,7 @@ tr:hover{background:var(--surface2)}
216
217
  .modal{width:98%;padding:12px}
217
218
  .form-group{margin-bottom:10px}
218
219
  .form-group label{font-size:12px}
220
+ .raw-collapsed{max-height:0 !important;padding:0 10px !important;overflow:hidden}
219
221
  }
220
222
  </style>
221
223
  </head>
@@ -240,7 +242,7 @@ tr:hover{background:var(--surface2)}
240
242
  <div class="nav-item" data-tooltip="查看日志" onclick="showPage('logs')"><span class="icon">📋</span><span class="icon-text">查看日志</span></div>
241
243
  <div class="nav-item" data-tooltip="任务记录" onclick="showPage('tasks')"><span class="icon">📌</span><span class="icon-text">任务记录</span></div>
242
244
  </div>
243
- <div style="padding:12px;border-top:1px solid var(--border);font-size:12px;color:var(--text2)" class="sidebar-footer-text">
245
+ <div style="padding:12px;border-top:1px solid var(--border);font-size:12px;color:var(--text2);flex-shrink:0" class="sidebar-footer-text">
244
246
  <span id="sidebarVersion">v...</span>
245
247
  <span id="updateBadge" style="display:none;margin-left:6px;color:var(--danger);font-weight:bold;cursor:pointer" onclick="doUpdate()" title="点击更新">[有新版本]</span>
246
248
  · <a href="#" onclick="api('/api/status').then(r=>showToast('Running: '+r.running,'success'))" style="color:var(--primary)">状态</a>
@@ -976,9 +978,101 @@ async function _loadSessionMessages(){
976
978
  html+='</div>';
977
979
  if(hasMore)html+=`<button class="btn btn-ghost mt-8" onclick="window._viewSessionOffset=${offset+100};_loadSessionMessages()">加载更多...</button>`;
978
980
  html+='<div class="flex gap-8 mt-8"><button class="btn btn-ghost" onclick="renderSessions()">返回</button>';
981
+ html+=`<button class="btn" style="background:var(--accent);color:#fff" onclick="viewSessionRaw('${escHtml(sid)}')">Raw 原始消息</button>`;
979
982
  html+=`<button class="btn btn-primary" onclick="enterSession('${escHtml(sid)}','${escHtml(sid.split('_web_')[0]||'default')}')">在聊天中查看完整记录</button></div>`;
980
983
  $('content').innerHTML=html;
981
984
  }
985
+ // ========== Raw 原始消息查看 ==========
986
+ async function viewSessionRaw(sid){
987
+ const msgs=await api(`/api/session/raw?sid=${encodeURIComponent(sid)}&limit=5000`);
988
+ if(!Array.isArray(msgs)){showToast('加载失败','danger');return}
989
+ // 按时间分组(同秒内合并)
990
+ const keyLabelMap={'llm_output':'LLM 输出','tool_call':'工具调用','tool_result':'工具结果','reasoning':'推理过程','conversation_insight':'会话洞察','':'对话','llm_request':'LLM 请求'};
991
+ let html=`<h3 style="margin-bottom:12px">Raw: ${escHtml(sid)} <span class="badge badge-blue">${msgs.length} 条</span></h3>`;
992
+ // 筛选按钮
993
+ html+=`<div style="margin-bottom:10px;display:flex;gap:6px;flex-wrap:wrap" id="rawFilterBar">`;
994
+ html+=`<button class="btn btn-sm" style="background:var(--accent);color:#fff" data-filter="all" onclick="rawFilter('all',this)">全部</button>`;
995
+ // 收集所有 key 类型
996
+ const keys=[...new Set(msgs.map(m=>m.key||''))];
997
+ for(const k of keys){
998
+ const label=keyLabelMap[k]||k||'对话';
999
+ const count=msgs.filter(m=>(m.key||'')===k).length;
1000
+ html+=`<button class="btn btn-sm btn-ghost" data-filter="${escHtml(k)}" onclick="rawFilter('${escHtml(k)}',this)">${escHtml(label)} (${count})</button>`;
1001
+ }
1002
+ html+=`</div>`;
1003
+ // 时间索引导航
1004
+ html+=`<div style="margin-bottom:8px;font-size:12px;color:var(--text3)" id="rawTimeNav"></div>`;
1005
+ // 消息列表
1006
+ html+=`<div style="max-height:65vh;overflow-y:auto;font-family:monospace" id="rawMsgList">`;
1007
+ for(let i=0;i<msgs.length;i++){
1008
+ const m=msgs[i];
1009
+ const role=m.role||'?';
1010
+ const key=m.key||'';
1011
+ const time=(m.time||'').slice(0,19);
1012
+ const content=(m.content||'');
1013
+ const keyLabel=keyLabelMap[key]||key;
1014
+ // 颜色标识
1015
+ let borderColor='var(--border)';
1016
+ let bgColor='var(--surface)';
1017
+ if(key==='llm_output'){borderColor='#e6a817';bgColor='#1a1700'}
1018
+ else if(key==='tool_call'){borderColor='#3b82f6';bgColor='#001029'}
1019
+ else if(key==='tool_result'){borderColor='#22c55e';bgColor='#001a0d'}
1020
+ else if(key==='reasoning'){borderColor='#a855f7';bgColor='#0d0020'}
1021
+ else if(role==='user'){borderColor='var(--primary)';bgColor='var(--surface)'}
1022
+ else if(role==='assistant'){borderColor='#6b7280';bgColor='var(--surface2)'}
1023
+ const mid='raw_'+i;
1024
+ html+=`<div class="raw-item" data-key="${escHtml(key)}" data-time="${escHtml(time)}" style="margin:2px 0;border-left:3px solid ${borderColor};background:${bgColor};border-radius:0 4px 4px 0;overflow:hidden">`;
1025
+ html+=`<div style="padding:4px 10px;font-size:11px;color:var(--text3);display:flex;justify-content:space-between;align-items:center;cursor:pointer" onclick="document.getElementById('${mid}').classList.toggle('raw-collapsed')">`;
1026
+ html+=`<span><span style="color:var(--text);font-weight:600">${escHtml(role)}</span>`;
1027
+ if(keyLabel)html+=` <span class="badge badge-blue" style="font-size:10px">${escHtml(keyLabel)}</span>`;
1028
+ html+=`</span>`;
1029
+ html+=`<span>${escHtml(time)} <span style="margin-left:4px;opacity:0.5">${content.length}字符</span></span>`;
1030
+ html+=`</div>`;
1031
+ html+=`<div id="${mid}" class="raw-body" style="padding:4px 10px 8px;font-size:12px;white-space:pre-wrap;word-break:break-all;color:var(--text2);max-height:400px;overflow-y:auto;transition:max-height 0.2s">`;
1032
+ html+=escHtml(content.length>8000?content.slice(0,8000)+'\n... (共'+content.length+'字符)':content);
1033
+ if(content.length>8000)html+=`<button class="btn btn-sm btn-ghost" style="margin-top:4px;font-size:10px" onclick="event.stopPropagation();this.parentElement.textContent=this.dataset.full;this.remove()" data-full="${escHtml(content).replace(/"/g,'&quot;')}">展开全部 (${content.length}字符)</button>`;
1034
+ html+=`</div></div>`;
1035
+ }
1036
+ html+=`</div>`;
1037
+ html+=`<div class="flex gap-8 mt-8"><button class="btn btn-ghost" onclick="viewSession('${escHtml(sid)}')">返回查看</button>`;
1038
+ html+=`<button class="btn btn-ghost" onclick="renderSessions()">返回会话列表</button></div>`;
1039
+ $('content').innerHTML=html;
1040
+ // 生成时间索引
1041
+ _buildTimeNav(msgs);
1042
+ }
1043
+ function rawFilter(key,btn){
1044
+ const items=document.querySelectorAll('.raw-item');
1045
+ for(const item of items){
1046
+ if(key==='all'||item.dataset.key===key){item.style.display=''}
1047
+ else{item.style.display='none'}
1048
+ }
1049
+ // 更新按钮样式
1050
+ const bar=document.getElementById('rawFilterBar');
1051
+ if(bar){
1052
+ bar.querySelectorAll('.btn').forEach(b=>{b.className='btn btn-sm btn-ghost'});
1053
+ if(btn)btn.className='btn btn-sm';
1054
+ if(btn)btn.style.background='var(--accent)';
1055
+ if(btn)btn.style.color='#fff';
1056
+ }
1057
+ }
1058
+ function _buildTimeNav(msgs){
1059
+ // 按分钟分组生成时间跳转锚点
1060
+ const nav=document.getElementById('rawTimeNav');
1061
+ if(!nav||!msgs.length)return;
1062
+ const minutes={};
1063
+ for(let i=0;i<msgs.length;i++){
1064
+ const t=(msgs[i].time||'').slice(0,16); // YYYY-MM-DDTHH:MM
1065
+ if(!minutes[t])minutes[t]=[];
1066
+ minutes[t].push(i);
1067
+ }
1068
+ const times=Object.keys(minutes);
1069
+ if(times.length<=1)return;
1070
+ let navHtml='时间索引: ';
1071
+ for(const t of times){
1072
+ navHtml+=`<a href="javascript:void(0)" style="color:var(--accent);margin-right:8px;text-decoration:none" onclick="document.querySelectorAll('.raw-item')[${minutes[t][0]}].scrollIntoView({behavior:'smooth',block:'center'})">${escHtml(t.slice(11))}</a>`;
1073
+ }
1074
+ nav.innerHTML=navHtml;
1075
+ }
982
1076
  async function clearSession(sid){await api(`/api/sessions/${encodeURIComponent(sid)}`,{method:'DELETE'});renderSessions()}
983
1077
  // 切入会话: 打开聊天页面并自动加载指定会话
984
1078
  function enterSession(sid,agentName){