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.
- package/agents/main_agent.py +4 -1
- package/memory/manager.py +8 -4
- package/package.json +1 -1
- package/web/api_server.py +9 -4
- package/web/ui/chat/chat_main.js +60 -22
package/agents/main_agent.py
CHANGED
|
@@ -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
|
-
#
|
|
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', '
|
|
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
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
|
|
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'
|
|
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
|
|
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
|
|
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
|
|
package/web/ui/chat/chat_main.js
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
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
|
-
//
|
|
2172
|
-
|
|
2173
|
-
|
|
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:
|
|
2181
|
-
tool_name: toolName,
|
|
2182
|
-
params:
|
|
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
|
-
|
|
2219
|
-
|
|
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:
|
|
2227
|
-
tool_name: toolName,
|
|
2228
|
-
params:
|
|
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
|
-
|
|
2258
|
-
|
|
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:
|
|
2266
|
-
tool_name: toolName,
|
|
2267
|
-
params:
|
|
2303
|
+
title: _tcParts4.title,
|
|
2304
|
+
tool_name: _tcParts4.toolName,
|
|
2305
|
+
params: _tcParts4.params || undefined,
|
|
2268
2306
|
status: 'done',
|
|
2269
2307
|
}
|
|
2270
2308
|
});
|