myagent-ai 1.15.0 → 1.15.1

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.
@@ -835,6 +835,7 @@ class MainAgent(BaseAgent):
835
835
  "v2_tool_start",
836
836
  {"tool": {
837
837
  "toolname": tool_name,
838
+ "beforecalltext": before_call,
838
839
  "parms": truncate_str(parms, 500),
839
840
  "timeout": timeout,
840
841
  "callback": should_callback,
@@ -1028,10 +1029,12 @@ class MainAgent(BaseAgent):
1028
1029
 
1029
1030
  # 保存工具调用到会话记忆
1030
1031
  if self.memory:
1032
+ # 构建工具调用记录,包含 beforecalltext 作为标题
1033
+ tool_call_title = before_call if before_call else f"调用工具: {tool_name}"
1031
1034
  self.memory.add_session(
1032
1035
  session_id=context.session_id,
1033
1036
  role="assistant",
1034
- content=f"调用工具: {tool_name}\n参数: {truncate_str(parms, 1000)}",
1037
+ content=f"{tool_call_title}\n调用工具: {tool_name}\n参数: {truncate_str(parms, 1000)}",
1035
1038
  key="tool_call",
1036
1039
  importance=0.4,
1037
1040
  )
package/memory/manager.py CHANGED
@@ -290,12 +290,16 @@ class MemoryManager:
290
290
  return self._insert(entry)
291
291
 
292
292
  def get_conversation(self, session_id, limit=500, include_roles=None) -> List[MemoryEntry]:
293
- """获取对话历史(session 分类中 role 非空的条目),按时间正序排列。"""
293
+ """获取对话历史(session 分类中 role 非空的条目),按时间正序排列。
294
+
295
+ 只排除纯内部审计条目(llm_output 原始LLM输出、conversation_insight 记忆提炼)。
296
+ tool_call 和 tool_result 会返回给前端以展示完整的工具调用过程。
297
+ """
294
298
  conn = self._get_conn()
295
- # 排除内部系统条目(llm_output, tool_call, tool_result, conversation_insight)
296
- sql = """SELECT * FROM memories
299
+ # 只排除纯内部审计条目,保留 tool_call/tool_result 供前端展示
300
+ sql = """SELECT * FROM memories
297
301
  WHERE session_id = ? AND category = 'session' AND role != ''
298
- AND key NOT IN ('llm_output', 'tool_call', 'tool_result', 'conversation_insight')
302
+ AND key NOT IN ('llm_output', 'conversation_insight')
299
303
  ORDER BY created_at ASC LIMIT ?"""
300
304
  rows = conn.execute(sql, (session_id, limit)).fetchall()
301
305
  entries = [MemoryEntry.from_row(row) for row in rows]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.15.0",
3
+ "version": "1.15.1",
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
@@ -2443,16 +2443,21 @@ class ApiServer:
2443
2443
  async def handle_list_sessions(self, request):
2444
2444
  if not self.core.memory: return web.json_response([])
2445
2445
  agent = request.query.get("agent", "")
2446
+ # 只统计用户可见的消息数(排除 llm_output 和 conversation_insight)
2446
2447
  if agent:
2447
2448
  prefix = f"{agent}_"
2448
2449
  rows = self.core.memory._get_conn().execute(
2449
2450
  "SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last FROM memories "
2450
- "WHERE category = 'session' AND session_id LIKE ? GROUP BY session_id ORDER BY last DESC LIMIT 100",
2451
+ "WHERE category = 'session' AND role != '' "
2452
+ "AND key NOT IN ('llm_output', 'conversation_insight') "
2453
+ "AND session_id LIKE ? GROUP BY session_id ORDER BY last DESC LIMIT 100",
2451
2454
  (prefix + "%",)).fetchall()
2452
2455
  else:
2453
2456
  rows = self.core.memory._get_conn().execute(
2454
2457
  "SELECT DISTINCT session_id, COUNT(*) as cnt, MAX(created_at) as last FROM memories "
2455
- "WHERE category = 'session' GROUP BY session_id ORDER BY last DESC LIMIT 100").fetchall()
2458
+ "WHERE category = 'session' AND role != '' "
2459
+ "AND key NOT IN ('llm_output', 'conversation_insight') "
2460
+ "GROUP BY session_id ORDER BY last DESC LIMIT 100").fetchall()
2456
2461
  sessions = [{"id": r["session_id"], "messages": r["cnt"], "last": r["last"]} for r in rows]
2457
2462
  # 批量获取自定义会话名称
2458
2463
  sids = [s["id"] for s in sessions]
@@ -2513,7 +2518,7 @@ class ApiServer:
2513
2518
  offset = int(request.query.get("offset", 0))
2514
2519
  entries = self.core.memory.get_conversation(sid, limit=limit + offset)
2515
2520
  entries = entries[offset:]
2516
- # Filter out internal entries (LLM raw output, tool calls/results)
2521
+ # Filter out internal entries (LLM raw output only)
2517
2522
  entries = [e for e in entries if (e.key or "") not in self._HIDDEN_KEYS]
2518
2523
  return web.json_response([{"role": e.role, "content": e.content, "time": e.created_at, "key": e.key or ""} for e in entries])
2519
2524
 
@@ -2527,7 +2532,7 @@ class ApiServer:
2527
2532
  offset = int(request.query.get("offset", 0))
2528
2533
  entries = self.core.memory.get_conversation(sid, limit=limit + offset)
2529
2534
  entries = entries[offset:]
2530
- # Filter out internal entries (LLM raw output, tool calls/results)
2535
+ # Filter out internal entries (LLM raw output only)
2531
2536
  entries = [e for e in entries if (e.key or "") not in self._HIDDEN_KEYS]
2532
2537
  return web.json_response([{"role": e.role, "content": e.content, "time": e.created_at, "key": e.key or ""} for e in entries])
2533
2538
 
@@ -2102,6 +2102,43 @@ async function clearCurrentChat() {
2102
2102
  // tool_result→ role="tool", key="tool_result"
2103
2103
  //
2104
2104
  // Result: user → [assistant { text → tool_call → tool_result → text → ... }] → user
2105
+
2106
+ // 解析 tool_call 消息内容,兼容新旧格式
2107
+ // 新格式: "beforecalltext\n调用工具: xxx\n参数: yyy"
2108
+ // 旧格式: "调用工具: xxx\n参数: yyy"
2109
+ function parseToolCallContent(content) {
2110
+ if (!content) return { title: '调用工具', toolName: '', params: '' };
2111
+ var lines = content.split('\n');
2112
+ var title = '';
2113
+ var toolName = '';
2114
+ var params = '';
2115
+ // 查找 "调用工具:" 行
2116
+ for (var li = 0; li < lines.length; li++) {
2117
+ var line = lines[li].trim();
2118
+ var m = line.match(/^调用工具:\s*(\S+)/);
2119
+ if (m) {
2120
+ toolName = m[1];
2121
+ break;
2122
+ }
2123
+ }
2124
+ // 查找 "参数:" 行
2125
+ for (var li2 = 0; li2 < lines.length; li2++) {
2126
+ var line2 = lines[li2].trim();
2127
+ var m2 = line2.match(/^参数:\s*([\s\S]*)/);
2128
+ if (m2) {
2129
+ params = m2[1].trim();
2130
+ break;
2131
+ }
2132
+ }
2133
+ // 标题: 如果第一行不是"调用工具:",则使用第一行作为 beforecalltext 标题
2134
+ if (lines[0] && !lines[0].trim().startsWith('调用工具:')) {
2135
+ title = lines[0].trim();
2136
+ } else {
2137
+ title = toolName ? ('调用工具: ' + toolName) : content.substring(0, 100);
2138
+ }
2139
+ return { title: title, toolName: toolName, params: params };
2140
+ }
2141
+
2105
2142
  function groupHistoryMessages(messages) {
2106
2143
  if (!Array.isArray(messages) || messages.length === 0) return messages;
2107
2144
 
@@ -2122,14 +2159,18 @@ function groupHistoryMessages(messages) {
2122
2159
 
2123
2160
  // Process the first assistant message
2124
2161
  if (msg.key === 'tool_call') {
2125
- const toolName = (msg.content.match(/^调用工具:\s*(\S+)/) || [])[1] || '';
2162
+ // 新格式: beforecalltext\n调用工具: xxx\n参数: yyy
2163
+ // 旧格式: 调用工具: xxx\n参数: yyy
2164
+ var _tcParts = msg._parsedToolCall || parseToolCallContent(msg.content);
2165
+ msg._parsedToolCall = _tcParts; // 缓存
2126
2166
  parts.push({
2127
2167
  type: 'exec',
2128
2168
  data: {
2129
2169
  id: _evtId++,
2130
2170
  type: 'tool_call',
2131
- title: toolName ? ('调用工具: ' + toolName) : msg.content.substring(0, 100),
2132
- tool_name: toolName,
2171
+ title: _tcParts.title,
2172
+ tool_name: _tcParts.toolName,
2173
+ params: _tcParts.params || undefined,
2133
2174
  status: 'done',
2134
2175
  }
2135
2176
  });
@@ -2168,18 +2209,17 @@ function groupHistoryMessages(messages) {
2168
2209
  });
2169
2210
  i++;
2170
2211
  } else if (next.role === 'assistant' && next.key === 'tool_call') {
2171
- // Parse tool_call content: format is "调用工具: {name}\n参数: {parms}"
2172
- const toolName = (next.content.match(/^调用工具:\s*(\S+)/) || [])[1] || '';
2173
- const paramsMatch = next.content.match(/参数:\s*([\s\S]*)/);
2174
- const toolParams = paramsMatch ? paramsMatch[1].trim() : '';
2212
+ // 新格式: beforecalltext\n调用工具: xxx\n参数: yyy
2213
+ var _tcParts2 = next._parsedToolCall || parseToolCallContent(next.content);
2214
+ next._parsedToolCall = _tcParts2;
2175
2215
  parts.push({
2176
2216
  type: 'exec',
2177
2217
  data: {
2178
2218
  id: _evtId++,
2179
2219
  type: 'tool_call',
2180
- title: toolName ? ('调用工具: ' + toolName) : next.content.substring(0, 100),
2181
- tool_name: toolName,
2182
- params: toolParams || undefined,
2220
+ title: _tcParts2.title,
2221
+ tool_name: _tcParts2.toolName,
2222
+ params: _tcParts2.params || undefined,
2183
2223
  status: 'done',
2184
2224
  }
2185
2225
  });
@@ -2215,17 +2255,16 @@ function groupHistoryMessages(messages) {
2215
2255
  const isCall = msg.key === 'tool_call';
2216
2256
 
2217
2257
  if (isCall) {
2218
- const toolName = (msg.content.match(/^调用工具:\s*(\S+)/) || [])[1] || '';
2219
- const paramsMatch = msg.content.match(/参数:\s*([\s\S]*)/);
2220
- const toolParams = paramsMatch ? paramsMatch[1].trim() : '';
2258
+ var _tcParts3 = msg._parsedToolCall || parseToolCallContent(msg.content);
2259
+ msg._parsedToolCall = _tcParts3;
2221
2260
  parts.push({
2222
2261
  type: 'exec',
2223
2262
  data: {
2224
2263
  id: _evtId++,
2225
2264
  type: 'tool_call',
2226
- title: toolName ? ('调用工具: ' + toolName) : msg.content.substring(0, 100),
2227
- tool_name: toolName,
2228
- params: toolParams || undefined,
2265
+ title: _tcParts3.title,
2266
+ tool_name: _tcParts3.toolName,
2267
+ params: _tcParts3.params || undefined,
2229
2268
  status: 'done',
2230
2269
  }
2231
2270
  });
@@ -2254,17 +2293,16 @@ function groupHistoryMessages(messages) {
2254
2293
  while (i < messages.length) {
2255
2294
  const next = messages[i];
2256
2295
  if (next.role === 'assistant' && next.key === 'tool_call') {
2257
- const toolName = (next.content.match(/^调用工具:\s*(\S+)/) || [])[1] || '';
2258
- const paramsMatch = next.content.match(/参数:\s*([\s\S]*)/);
2259
- const toolParams = paramsMatch ? paramsMatch[1].trim() : '';
2296
+ var _tcParts4 = next._parsedToolCall || parseToolCallContent(next.content);
2297
+ next._parsedToolCall = _tcParts4;
2260
2298
  parts.push({
2261
2299
  type: 'exec',
2262
2300
  data: {
2263
2301
  id: _evtId++,
2264
2302
  type: 'tool_call',
2265
- title: toolName ? ('调用工具: ' + toolName) : next.content.substring(0, 100),
2266
- tool_name: toolName,
2267
- params: toolParams || undefined,
2303
+ title: _tcParts4.title,
2304
+ tool_name: _tcParts4.toolName,
2305
+ params: _tcParts4.params || undefined,
2268
2306
  status: 'done',
2269
2307
  }
2270
2308
  });