myagent-ai 1.26.7 → 1.26.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.
@@ -52,7 +52,7 @@ class MainAgent(BaseAgent):
52
52
  <mainsubject>当前对话的6字以内标题(每轮都需输出,系统会每3轮自动更新会话名称)</mainsubject>
53
53
  <usersays_correct>通过修正识别错误、调整标点,结合上下文,将用户语音转写文本"usersays"修正为更准确的文本,但尽量少改动。如"usersays"为空,则此处为空。</usersays_correct>
54
54
  <response><reply>展示给用户的文本,格式上尽量使用md格式,直观形象展示,甚至可以包括超链接、表格等。内容上,针对用户问题,直接回应问题;针对任务,开始的时候,告诉用户,为完成任务,准备如何开展工作;执行过程中,根据工具调用结果,简单展示任务进展;任务完成后的详细最终总结。注意:这是给用户展示信息的最重要标签,尽量不要跟上次回复重复,执行过程展示内容尽量简洁,执行总结可以丰富一点。</reply><toolstocal>
55
- <tool><beforecalltext>展示给用户的简单工具调用信息。格式:先使用"接下来、下一步、接着、现在、然后、最后、等下"等连接词➕调用"工具名"。</beforecalltext><toolname>工具名,用于后台解析器解析调用工具</toolname><parms>调用工具的JSON格式参数对象,如格式: {"query": "搜索关键词", "num": 5}</parms><timeout>最多给它执行多久(秒),工具调用超过这个时限会立即回调大语言模型,方便调整工具使用</timeout></tool>
55
+ <tool><beforecalltext>展示给用户的简单工具调用信息。格式:先使用"接下来、下一步、接着、现在、然后、最后、等下"等连接词➕调用"工具名"。</beforecalltext><toolname>工具名,用于后台解析器解析调用工具</toolname><parms>调用工具的XML格式参数,每个参数用独立子标签表示,如: <command>要执行的命令</command> <query>搜索关键词</query><num>5</num></parms><timeout>最多给它执行多久(秒),工具调用超过这个时限会立即回调大语言模型,方便调整工具使用</timeout></tool>
56
56
  </toolstocal>
57
57
  </response>
58
58
  <task_plan>若"context"包含非空"task_plan",则更新它:若任务条数已超8,则精简为3条,若主题发生明显变化,重新设计任务列表。若"context"包含空"task_plan",则先评估任务复杂度,针对单次查询、简单问答、格式转换、单文件修改、简单计算等简单任务,若预计操作步骤不超过2步,则此处输出为空,不创建任务列表;针对多文件修改、需要调研+实现+测试、涉及多个模块联动等复杂任务,如预计超过2步操作,则以Markdown列表格式制定新任务列表。格式:每项用 "- [ ] 任务描述" 或 "- [x] 已完成任务",含完成状态标记,排序按已完成在前。</task_plan>
@@ -78,7 +78,7 @@ class MainAgent(BaseAgent):
78
78
  4. 文件自动发送与下载链接: docx-create、xlsx-create、ppt-create、pdf-create 等命令执行成功后会**自动**将文件发送给用户(无需手动调用 send-file)。系统会返回包含下载链接的文件卡片,LLM 不需要自行拼接文件链接。仅在需要发送其他独立文件(如已存在的文件)时,才使用 myagent-ai send-file <文件路径> [描述]。向用户展示下载链接时,务必使用 Markdown 超链接格式: [文件名](完整URL)。
79
79
 
80
80
  **command**(执行命令行,所有操作都通过它完成):
81
- <tool><toolname>command</toolname><parms>{"command": "要执行的命令"}</parms><timeout>超时秒数</timeout></tool>
81
+ <tool><toolname>command</toolname><parms><command>要执行的命令</command></parms><timeout>超时秒数</timeout></tool>
82
82
 
83
83
  【重要】命令执行规则:
84
84
  - Shell 原生命令(ls/cat/grep/ps/df/uname/python3/pip/npm/git/curl/wget 等)直接执行,不要加任何前缀
@@ -123,30 +123,30 @@ GUI桌面 (仅Windows/macOS):
123
123
  - 播放音频/视频: myagent-ai playaudio/playvideo --url URL [--title 标题]
124
124
 
125
125
  调用示例:
126
- <tool><toolname>command</toolname><parms>{"command": "ls -la /tmp && df -h && python3 --version"}</parms><timeout>10</timeout></tool>
127
- <tool><toolname>command</toolname><parms>{"command": "myagent-ai search 人工智能最新进展"}</parms><timeout>15</timeout></tool>
128
- <tool><toolname>command</toolname><parms>{"command": "myagent-ai docx-create -c '{\"title\": \"报告\", \"sections\": [{\"heading\": \"摘要\", \"body\": \"内容\"}]}' -t 周报"}</parms><timeout>30</timeout></tool>
129
- <tool><toolname>command</toolname><parms>{"command": "cat /etc/os-release && uname -a && free -h"}</parms><timeout>10</timeout></tool>
126
+ <tool><toolname>command</toolname><parms><command>ls -la /tmp && df -h && python3 --version</command></parms><timeout>10</timeout></tool>
127
+ <tool><toolname>command</toolname><parms><command>myagent-ai search 人工智能最新进展</command></parms><timeout>15</timeout></tool>
128
+ <tool><toolname>command</toolname><parms><command>myagent-ai docx-create -c '{"title": "报告", "sections": [{"heading": "摘要", "body": "内容"}]}' -t 周报</command></parms><timeout>30</timeout></tool>
129
+ <tool><toolname>command</toolname><parms><command>cat /etc/os-release && uname -a && free -h</command></parms><timeout>10</timeout></tool>
130
130
 
131
131
  **file_send**(向用户发送文件,文件会以卡片形式显示在聊天中):
132
- <tool><toolname>file_send</toolname><parms>{"file_path": "文件的绝对路径", "description": "文件描述(可选)"}</parms><timeout>30</timeout></tool>
132
+ <tool><toolname>file_send</toolname><parms><file_path>文件的绝对路径</file_path><description>文件描述(可选)</description></parms><timeout>30</timeout></tool>
133
133
  - 当你需要把生成的文件(PDF、Excel、图片、脚本等)发送给用户时,直接使用此工具
134
134
  - 当你需要发送一个已存在的文件时,直接使用此工具
135
135
  - 不要把文件路径当成文本展示给用户,而是用 file_send 工具发送文件卡片
136
136
 
137
137
  **web_control**(网页控制器,在聊天中打开可操作的浏览器面板):
138
- <tool><toolname>web_control</toolname><parms>{"action": "open", "url": "https://example.com"}</parms><timeout>30</timeout></tool>
139
- - 打开: {"action": "open", "url": "URL"}
140
- - 导航: {"action": "navigate", "url": "URL", "session_id": "xxx"}
141
- - 获取内容: {"action": "get_content", "what": "text|html|url|title|links|images|forms|inputs", "session_id": "xxx"}
142
- - 点击: {"action": "click", "selector": "CSS选择器", "session_id": "xxx"}
143
- - 填写: {"action": "fill", "selector": "CSS选择器", "value": "内容", "session_id": "xxx"}
144
- - 滚动: {"action": "scroll", "direction": "up|down|top|bottom", "distance": 300, "session_id": "xxx"}
145
- - 执行JS: {"action": "evaluate", "script": "JS代码", "session_id": "xxx"}
146
- - 截图: {"action": "screenshot", "session_id": "xxx"}
147
- - 等待: {"action": "wait", "time": 1000}{"action": "wait", "selector": ".result", "timeout": 10}
148
- - Cookie: {"action": "set_cookies", "cookies": [...], "session_id": "xxx"}{"action": "get_cookies", "session_id": "xxx"}
149
- - 关闭: {"action": "close", "session_id": "xxx"}
138
+ <tool><toolname>web_control</toolname><parms><action>open</action><url>https://example.com</url></parms><timeout>30</timeout></tool>
139
+ - 打开: <parms><action>open</action><url>URL</url></parms>
140
+ - 导航: <parms><action>navigate</action><url>URL</url><session_id>xxx</session_id></parms>
141
+ - 获取内容: <parms><action>get_content</action><what>text|html|url|title|links|images|forms|inputs</what><session_id>xxx</session_id></parms>
142
+ - 点击: <parms><action>click</action><selector>CSS选择器</selector><session_id>xxx</session_id></parms>
143
+ - 填写: <parms><action>fill</action><selector>CSS选择器</selector><value>内容</value><session_id>xxx</session_id></parms>
144
+ - 滚动: <parms><action>scroll</action><direction>up|down|top|bottom</direction><distance>300</distance><session_id>xxx</session_id></parms>
145
+ - 执行JS: <parms><action>evaluate</action><script>JS代码</script><session_id>xxx</session_id></parms>
146
+ - 截图: <parms><action>screenshot</action><session_id>xxx</session_id></parms>
147
+ - 等待: <parms><action>wait</action><time>1000</time></parms><parms><action>wait</action><selector>.result</selector><timeout>10</timeout></parms>
148
+ - Cookie: <parms><action>set_cookies</action><cookies>[{"name":"key","value":"val"}]</cookies><session_id>xxx</session_id></parms><parms><action>get_cookies</action><session_id>xxx</session_id></parms>
149
+ - 关闭: <parms><action>close</action><session_id>xxx</session_id></parms>
150
150
 
151
151
  专业技能指令: 系统内置了丰富的专业技能指南(PDF/DOCX/XLSX/PPT 生成、图表绘制、前端开发等),通过 <get_knowledge> 请求相关技能指令。
152
152
  """
@@ -1651,16 +1651,24 @@ GUI桌面 (仅Windows/macOS):
1651
1651
  stream_callback: Optional[Callable] = None,
1652
1652
  sent_files: Optional[List[Dict[str, Any]]] = None,
1653
1653
  ) -> Dict[str, Any]:
1654
- """[v1.22.0] V2 工具执行 — 统一分发到 ToolDispatcher"""
1654
+ """[v1.22.0] V2 工具执行 — 统一分发到 ToolDispatcher
1655
+ [v1.27.0] parms 使用 XML 子标签格式:
1656
+ <command>ls -la</command> → {"command": "ls -la"}
1657
+ <file_path>/tmp/a.txt</file_path><description>描述</description> → {"file_path": "/tmp/a.txt", "description": "描述"}
1658
+ """
1655
1659
  try:
1656
- import json as _json
1660
+ import re as _re
1657
1661
  import html as _html
1658
1662
  try:
1659
- # [v1.23.38] 防御性修复: 解码 HTML 实体 (&amp; → & 等)
1660
- # LLM 可能在 XML 输出中使用 &amp; 代替 &,导致 bash 命令失败
1661
1663
  _clean_parms = _html.unescape(parms_str) if parms_str else ""
1662
- params = _json.loads(_clean_parms) if _clean_parms else {}
1663
- except (_json.JSONDecodeError, TypeError):
1664
+ # XML 子标签解析: <key>value</key> {"key": "value"}
1665
+ params = {}
1666
+ for _tag_name, _tag_value in _re.findall(
1667
+ r"<([a-zA-Z_][a-zA-Z0-9_]*)\s*>([\s\S]*?)</\1\s*>",
1668
+ _clean_parms,
1669
+ ):
1670
+ params[_tag_name] = _tag_value.strip()
1671
+ except Exception:
1664
1672
  params = {"raw_input": parms_str}
1665
1673
 
1666
1674
  if self.dispatcher:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.26.7",
3
+ "version": "1.26.8",
4
4
  "description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
5
5
  "main": "main.py",
6
6
  "bin": {
@@ -116,7 +116,8 @@ INTERNAL_SERVICES: List[Dict[str, Any]] = [
116
116
  # CLI 子命令元数据 — 通过 command 工具间接调用
117
117
  # ==============================================================================
118
118
  # [v1.23.0] 这些命令由 scripts/cli.py 实现,LLM 通过 command 工具调用:
119
- # <toolname>command</toolname><parms>{"command": "myagent-ai <cmd> [args...]"}</parms>
119
+ # <toolname>command</toolname><parms><command>myagent-ai <cmd> [args...]</command></parms>
120
+ # [v1.27.0] parms 从 JSON 改为 XML 子标签格式
120
121
 
121
122
  CLI_COMMANDS: List[Dict[str, Any]] = [
122
123
  # ── 感知 ──
@@ -54,7 +54,17 @@ async function _loadSessionMessages(){
54
54
  const label=isResult?'工具执行结果':(isCall?'工具调用':'工具过程');
55
55
  const isOk=isResult&&!((m.content||'').includes('失败'));
56
56
  const badge=isResult?`<span class="badge ${isOk?'badge-green':'badge-red'}" style="margin-left:6px">${isOk?'成功':'失败'}</span>`:'';
57
- const tc=(m.content||'');
57
+ // [v1.27.0] 工具调用: 格式化参数行显示(提取"参数:"行并用统一格式化)
58
+ let tc=(m.content||'');
59
+ if(isCall && tc && typeof window.formatToolParamsPreview==='function'){
60
+ const lines=tc.split('\n');
61
+ const formatted=lines.map(l=>{
62
+ const pm=l.match(/^参数:\s*([\s\S]*)/);
63
+ if(pm){return '参数: '+window.formatToolParamsPreview(pm[1].trim(),500);}
64
+ return l;
65
+ }).join('\n');
66
+ tc=formatted;
67
+ }
58
68
  const tcTrunc=tc.length>800;
59
69
  html+=`<details style="margin:4px 0;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden" ${tcTrunc?'':'open'}><summary style="padding:8px 12px;cursor:pointer;font-size:13px;color:var(--text2);background:var(--surface2)">${icon} ${label}${badge}</summary><div style="padding:8px 12px;background:var(--surface);font-size:12px;white-space:pre-wrap;word-break:break-all;color:var(--text2)">${escHtml(tcTrunc?tc.slice(0,800)+'... (共'+tc.length+'字符)':'')}</div></details>`;
60
70
  } else {
@@ -3051,6 +3051,7 @@ async function clearCurrentChat() {
3051
3051
  // 推理思考 → role="assistant", key="reasoning"
3052
3052
 
3053
3053
  // 解析 tool_call 消息内容,兼容新旧格式
3054
+ // [v1.27.0] params 现在支持 XML 子标签和 JSON 两种格式
3054
3055
  function parseToolCallContent(content) {
3055
3056
  if (!content) return { title: '调用工具', toolName: '', params: '' };
3056
3057
  var lines = content.split('\n');
@@ -3066,7 +3067,12 @@ function parseToolCallContent(content) {
3066
3067
  var tcIdx = lines.findIndex(function(l) { return l.trim().match(/^调用工具:/); });
3067
3068
  var title = tcIdx > 0 ? lines.slice(0, tcIdx).join('\n').trim() : '';
3068
3069
  if (!title) title = toolName ? ('调用工具: ' + toolName) : '调用工具';
3069
- return { title: title, toolName: toolName, params: params };
3070
+ // [v1.27.0] 使用统一格式化函数生成显示用 params
3071
+ var displayParams = params;
3072
+ if (typeof window.formatToolParamsPreview === 'function' && params) {
3073
+ displayParams = window.formatToolParamsPreview(params, 300);
3074
+ }
3075
+ return { title: title, toolName: toolName, params: params, displayParams: displayParams };
3070
3076
  }
3071
3077
 
3072
3078
  // 解析 tool_result 消息: "[tool_name] 成功/失败\n{output}"
@@ -3094,7 +3100,7 @@ function groupHistoryMessages(messages) {
3094
3100
  if (key === 'tool_call') {
3095
3101
  var tc = m._parsedToolCall || parseToolCallContent(m.content);
3096
3102
  m._parsedToolCall = tc;
3097
- return { type: 'exec', data: { id: evtId, type: 'tool_call', title: tc.title, tool_name: tc.toolName, params: tc.params || undefined, status: 'done' } };
3103
+ return { type: 'exec', data: { id: evtId, type: 'tool_call', title: tc.title, tool_name: tc.toolName, params: tc.displayParams || tc.params || undefined, status: 'done' } };
3098
3104
  }
3099
3105
  if (m.role === 'tool') {
3100
3106
  var tr = parseToolResultContent(m.content);
@@ -3236,11 +3242,15 @@ function groupHistoryMessages(messages) {
3236
3242
  var ep = parts[ei];
3237
3243
  if (ep.type === 'exec' && ep.data.tool_name && (ep.data.tool_name === 'playaudio' || ep.data.tool_name === 'playvideo')) {
3238
3244
  try {
3239
- var mparams = typeof ep.data.params === 'string' ? JSON.parse(ep.data.params) : (ep.data.params || {});
3240
- var murl = mparams.url || '';
3245
+ // [v1.27.0] params 中提取 XML 子标签 <url> <title>
3246
+ var _p = ep.data.params || '';
3247
+ var _urlMatch = typeof _p === 'string' ? _p.match(/<url\s*>([\s\S]*?)<\/url\s*>/) : null;
3248
+ var murl = _urlMatch ? _urlMatch[1].trim() : '';
3249
+ var _titleMatch = typeof _p === 'string' ? _p.match(/<title\s*>([\s\S]*?)<\/title\s*>/) : null;
3250
+ var mtitle = _titleMatch ? _titleMatch[1].trim() : '';
3241
3251
  if (murl) {
3242
3252
  var mtype = ep.data.tool_name === 'playaudio' ? 'audio' : 'video';
3243
- mediaEmbeds.push({ media_type: mtype, embed_url: murl, title: mparams.title || '', original_url: murl });
3253
+ mediaEmbeds.push({ media_type: mtype, embed_url: murl, title: mtitle, original_url: murl });
3244
3254
  }
3245
3255
  } catch(mpe) { /* ignore parse errors */ }
3246
3256
  }
@@ -3253,7 +3263,13 @@ function groupHistoryMessages(messages) {
3253
3263
  var wp = parts[wi];
3254
3264
  if (wp.type === 'exec' && wp.data.tool_name === 'web_control') {
3255
3265
  try {
3256
- var wcparams = typeof wp.data.params === 'string' ? JSON.parse(wp.data.params) : (wp.data.params || {});
3266
+ // [v1.27.0] params 中提取 XML 子标签
3267
+ var _p = wp.data.params || '';
3268
+ var wcparams = {};
3269
+ if (typeof _p === 'string') {
3270
+ var _re = /<([a-zA-Z_][a-zA-Z0-9_]*)\s*>([\s\S]*?)<\/\1\s*>/g;
3271
+ var _m; while ((_m = _re.exec(_p)) !== null) { wcparams[_m[1]] = _m[2].trim(); }
3272
+ }
3257
3273
  wcEvents.push(wcparams);
3258
3274
  } catch(wce) { /* ignore */ }
3259
3275
  }
@@ -1108,6 +1108,31 @@ function _updateToolCardInDOM(msgIdx, partIdx) {
1108
1108
  targetCard.outerHTML = updatedHtml;
1109
1109
  }
1110
1110
 
1111
+ // ══════════════════════════════════════════════════════
1112
+ // ── [v1.27.0] 统一工具参数格式化 — XML 格式显示 ──
1113
+ // 所有页面共用此函数,将 raw parms 字符串格式化为人类可读的简短预览
1114
+ // ══════════════════════════════════════════════════════
1115
+ window.formatToolParamsPreview = function(rawParams, maxLen) {
1116
+ maxLen = maxLen || 200;
1117
+ if (!rawParams) return '';
1118
+ var str = (typeof rawParams === 'string') ? rawParams : JSON.stringify(rawParams);
1119
+ // XML 格式: 提取所有 <key>value</key> 对,格式化为 "key: value"
1120
+ var pairs = [];
1121
+ var re = /<([a-zA-Z_][a-zA-Z0-9_]*)\s*>([\s\S]*?)<\/\1\s*>/g;
1122
+ var m;
1123
+ while ((m = re.exec(str)) !== null) {
1124
+ var val = m[2].trim();
1125
+ if (val.length > 100) val = val.substring(0, 100) + '...';
1126
+ pairs.push(m[1] + ': ' + val);
1127
+ }
1128
+ if (pairs.length > 0) {
1129
+ var result = pairs.join(' | ');
1130
+ return result.length > maxLen ? result.substring(0, maxLen) + '...' : result;
1131
+ }
1132
+ // 非 XML: 直接截断返回
1133
+ return str.length > maxLen ? str.substring(0, maxLen) + '...' : str;
1134
+ };
1135
+
1111
1136
  function renderInlineExecEvent(data, msgIdx) {
1112
1137
  // V2 Tool Event handling (called with full part: {type:'v2_tool', data:{...}})
1113
1138
  if (data.type === 'v2_tool') {
@@ -1142,10 +1167,9 @@ function renderInlineExecEvent(data, msgIdx) {
1142
1167
  if (isResult && inner.result) {
1143
1168
  bodyHtml += '<button class="inline-exec-result-btn" onclick="showToolResultModal(' + msgIdx + ', \'' + inner.id + '\')">查看详情</button>';
1144
1169
  }
1145
- // Show params for tool_start
1170
+ // Show params for tool_start — [v1.27.0] 使用统一格式化函数
1146
1171
  if (isStart && inner.params) {
1147
- let paramPreview = typeof inner.params === 'string' ? inner.params : JSON.stringify(inner.params);
1148
- if (paramPreview.length > 200) paramPreview = paramPreview.substring(0, 200) + '...';
1172
+ let paramPreview = window.formatToolParamsPreview(inner.params, 200);
1149
1173
  bodyHtml += '<div class="inline-exec-code">' + escapeHtml(paramPreview) + '</div>';
1150
1174
  }
1151
1175
 
@@ -1184,10 +1208,9 @@ function renderInlineExecEvent(data, msgIdx) {
1184
1208
 
1185
1209
  // Build body content
1186
1210
  let bodyHtml = '';
1187
- // Params for tool_call/skill_call (合并卡片中 params 在折叠区域显示)
1211
+ // Params for tool_call/skill_call (合并卡片中 params 在折叠区域显示) — [v1.27.0] 统一格式化
1188
1212
  if (data.params && (data.type === 'tool_call' || data.type === 'skill_call') && !data.has_result) {
1189
- let paramPreview = typeof data.params === 'string' ? data.params : JSON.stringify(data.params);
1190
- if (paramPreview.length > 300) paramPreview = paramPreview.substring(0, 300) + '...';
1213
+ let paramPreview = window.formatToolParamsPreview(data.params, 300);
1191
1214
  bodyHtml += '<div class="inline-exec-code">' + escapeHtml(paramPreview) + '</div>';
1192
1215
  }
1193
1216
  // Code preview for code_exec/code_result
@@ -1198,8 +1221,7 @@ function renderInlineExecEvent(data, msgIdx) {
1198
1221
  if (data.has_result) {
1199
1222
  // 折叠的参数区域
1200
1223
  if (data.params) {
1201
- let paramPreview = typeof data.params === 'string' ? data.params : JSON.stringify(data.params);
1202
- if (paramPreview.length > 300) paramPreview = paramPreview.substring(0, 300) + '...';
1224
+ let paramPreview = window.formatToolParamsPreview(data.params, 300);
1203
1225
  bodyHtml += '<div class="tool-result-collapsible"><div class="tool-collapsible-toggle" onclick="this.parentElement.classList.toggle(\'collapsed\')">📋 参数</div><div class="tool-collapsible-body"><div class="inline-exec-code">' + escapeHtml(paramPreview) + '</div></div></div>';
1204
1226
  }
1205
1227
  // 结果摘要