myagent-ai 1.20.8 → 1.20.10

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.
Files changed (63) hide show
  1. package/config.py +1 -0
  2. package/core/context_builder.py +17 -0
  3. package/core/deps_checker.py +11 -0
  4. package/core/vnc_manager.py +18 -6
  5. package/core/web_control.py +19 -1
  6. package/data/novnc/lib/base64.js +100 -0
  7. package/data/novnc/lib/crypto/aes.js +481 -0
  8. package/data/novnc/lib/crypto/bigint.js +41 -0
  9. package/data/novnc/lib/crypto/crypto.js +109 -0
  10. package/data/novnc/lib/crypto/des.js +374 -0
  11. package/data/novnc/lib/crypto/dh.js +81 -0
  12. package/data/novnc/lib/crypto/md5.js +97 -0
  13. package/data/novnc/lib/crypto/rsa.js +312 -0
  14. package/data/novnc/lib/decoders/copyrect.js +40 -0
  15. package/data/novnc/lib/decoders/hextile.js +195 -0
  16. package/data/novnc/lib/decoders/jpeg.js +175 -0
  17. package/data/novnc/lib/decoders/raw.js +66 -0
  18. package/data/novnc/lib/decoders/rre.js +52 -0
  19. package/data/novnc/lib/decoders/tight.js +363 -0
  20. package/data/novnc/lib/decoders/tightpng.js +51 -0
  21. package/data/novnc/lib/decoders/zrle.js +192 -0
  22. package/data/novnc/lib/deflator.js +88 -0
  23. package/data/novnc/lib/display.js +527 -0
  24. package/data/novnc/lib/encodings.js +63 -0
  25. package/data/novnc/lib/inflator.js +77 -0
  26. package/data/novnc/lib/input/domkeytable.js +313 -0
  27. package/data/novnc/lib/input/fixedkeys.js +127 -0
  28. package/data/novnc/lib/input/gesturehandler.js +573 -0
  29. package/data/novnc/lib/input/keyboard.js +292 -0
  30. package/data/novnc/lib/input/keysym.js +878 -0
  31. package/data/novnc/lib/input/keysymdef.js +1351 -0
  32. package/data/novnc/lib/input/util.js +217 -0
  33. package/data/novnc/lib/input/vkeys.js +121 -0
  34. package/data/novnc/lib/input/xtscancodes.js +343 -0
  35. package/data/novnc/lib/ra2.js +535 -0
  36. package/data/novnc/lib/rfb.js +3225 -0
  37. package/data/novnc/lib/util/browser.js +147 -0
  38. package/data/novnc/lib/util/cursor.js +269 -0
  39. package/data/novnc/lib/util/element.js +41 -0
  40. package/data/novnc/lib/util/events.js +133 -0
  41. package/data/novnc/lib/util/eventtarget.js +53 -0
  42. package/data/novnc/lib/util/int.js +21 -0
  43. package/data/novnc/lib/util/logging.js +56 -0
  44. package/data/novnc/lib/util/strings.js +36 -0
  45. package/data/novnc/lib/vendor/pako/lib/utils/common.js +55 -0
  46. package/data/novnc/lib/vendor/pako/lib/zlib/adler32.js +29 -0
  47. package/data/novnc/lib/vendor/pako/lib/zlib/constants.js +47 -0
  48. package/data/novnc/lib/vendor/pako/lib/zlib/crc32.js +35 -0
  49. package/data/novnc/lib/vendor/pako/lib/zlib/deflate.js +1721 -0
  50. package/data/novnc/lib/vendor/pako/lib/zlib/gzheader.js +41 -0
  51. package/data/novnc/lib/vendor/pako/lib/zlib/inffast.js +327 -0
  52. package/data/novnc/lib/vendor/pako/lib/zlib/inflate.js +1602 -0
  53. package/data/novnc/lib/vendor/pako/lib/zlib/inftrees.js +310 -0
  54. package/data/novnc/lib/vendor/pako/lib/zlib/messages.js +25 -0
  55. package/data/novnc/lib/vendor/pako/lib/zlib/trees.js +1150 -0
  56. package/data/novnc/lib/vendor/pako/lib/zlib/zstream.js +30 -0
  57. package/data/novnc/lib/websock.js +395 -0
  58. package/main.py +53 -1
  59. package/package.json +1 -1
  60. package/skills/agent_tool_skill.py +113 -0
  61. package/skills/file_send.py +44 -2
  62. package/web/api_server.py +278 -108
  63. package/web/ui/chat/chat_main.js +27 -14
package/config.py CHANGED
@@ -155,6 +155,7 @@ class AppConfig:
155
155
  data_dir: str = "" # 数据目录,默认 ~/.myagent/
156
156
  language: str = "zh-CN"
157
157
  timezone: str = "Asia/Shanghai" # 时区,用于生成时间戳和提示词中的当前时间
158
+ public_url: str = "" # [v1.20.8] 公开访问 URL(用于生成文件下载链接),如 http://your-server.com:8767
158
159
 
159
160
 
160
161
  # ==============================================================================
@@ -238,12 +238,29 @@ class ContextBuilder:
238
238
  f"描述: {safe_desc}",
239
239
  ]
240
240
 
241
+ # [v1.20.8] 注入工作目录信息,让 Agent 知道文件应保存到哪里
242
+ work_dir = self._get_workspace_dir()
243
+ if work_dir:
244
+ parts.append(f"工作目录: {_xml_escape(str(work_dir))}")
245
+ parts.append(f"文件保存说明: 通过 file_write 或代码生成的文件请保存到工作目录下的 userfiles 子目录。发送文件给用户请使用 file_send 工具。")
246
+
241
247
  if agent_override_prompt:
242
248
  parts.append(f"附加指令: {_xml_escape(agent_override_prompt)}")
243
249
 
244
250
  parts.append("</whomi>")
245
251
  return "\n".join(parts)
246
252
 
253
+ def _get_workspace_dir(self) -> Optional[str]:
254
+ """[v1.20.8] 获取工作目录路径(~/.myagent/data/workspace)"""
255
+ try:
256
+ from config import ConfigManager
257
+ cm = ConfigManager()
258
+ wd = cm.data_dir / "workspace"
259
+ wd.mkdir(parents=True, exist_ok=True)
260
+ return str(wd)
261
+ except Exception:
262
+ return None
263
+
247
264
  def _build_memory(self, query: str, session_id: str, recall: str = "", memory_context_prompt: str = "") -> str:
248
265
  """
249
266
  构建 <automemory> 和 <recall_memory> 段落 —— 双层记忆检索结果。
@@ -126,6 +126,17 @@ DEPENDENCIES: List[DepInfo] = [
126
126
  # ── 远程桌面 (VNC) [v1.17.0] ──
127
127
  # VNC 依赖通过 apt 安装 (xvfb, x11vnc),websockify 通过 pip 安装
128
128
  # 实际检测和安装在 VNCManager.ensure_dependencies() 中完成
129
+
130
+ # ── 系统工具 [v1.20.9] ──
131
+ # ffmpeg: SenseVoice 音频解码必需 (WAV→16kHz转换)
132
+ ]
133
+
134
+ # [v1.20.9] 系统级工具依赖列表(非 Python 包,需通过系统包管理器安装)
135
+ SYSTEM_TOOLS = [
136
+ {"name": "ffmpeg", "note": "FFmpeg 多媒体处理工具 (SenseVoice STT 必需, 用于音频格式转换)",
137
+ "install": {"linux": "sudo apt install ffmpeg", "macos": "brew install ffmpeg"}},
138
+ {"name": "convert", "note": "ImageMagick 图像处理工具 (VNC 截图备用)",
139
+ "install": {"linux": "sudo apt install imagemagick", "macos": "brew install imagemagick"}},
129
140
  ]
130
141
 
131
142
 
@@ -335,15 +335,23 @@ class VNCManager:
335
335
  """查找 noVNC web 文件目录
336
336
 
337
337
  搜索顺序:
338
- 1. /usr/share/novnc (apt 安装)
339
- 2. /usr/local/share/novnc
340
- 3. pip 安装的 websockify 自带 novnc
338
+ 1. 项目内置 noVNC (data/novnc/)
339
+ 2. /usr/share/novnc (apt 安装)
340
+ 3. /usr/local/share/novnc
341
+ 4. pip 安装的 websockify 自带 novnc
341
342
  """
342
- search_paths = [
343
+ search_paths = []
344
+
345
+ # [v1.20.9] 优先搜索项目内置 noVNC
346
+ _builtin_novnc = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'data', 'novnc')
347
+ if os.path.isdir(_builtin_novnc):
348
+ search_paths.append(_builtin_novnc)
349
+
350
+ search_paths.extend([
343
351
  "/usr/share/novnc",
344
352
  "/usr/local/share/novnc",
345
353
  "/opt/novnc",
346
- ]
354
+ ])
347
355
 
348
356
  # 也搜索 pip 安装路径
349
357
  try:
@@ -362,12 +370,16 @@ class VNCManager:
362
370
 
363
371
  for path in search_paths:
364
372
  if os.path.isdir(path):
365
- # 检查是否有 vnc.html
373
+ # 检查是否有 vnc.html(完整 noVNC 安装)
366
374
  for sub in ["", "/vnc_lite", "/vnc"]:
367
375
  html = os.path.join(path + sub, "vnc.html")
368
376
  vnc_lite = os.path.join(path + sub, "vnc_lite.html")
369
377
  if os.path.isfile(html) or os.path.isfile(vnc_lite):
370
378
  return path + sub if sub else path
379
+ # [v1.20.9] 检查是否有 lib/rfb.js(内置精简 noVNC)
380
+ rfb_js = os.path.join(path, "lib", "rfb.js")
381
+ if os.path.isfile(rfb_js):
382
+ return path
371
383
 
372
384
  return None
373
385
 
@@ -415,12 +415,30 @@ class WebControlManager:
415
415
  """
416
416
  向客户端下发命令并等待结果。
417
417
  Agent 工具调用线程阻塞在此, 直到客户端返回结果或超时。
418
+
419
+ [v1.20.9] 修复: 如果面板尚未打开(刚执行了 open 但客户端还没加载完成),
420
+ 会等待最多 15 秒让面板打开,而不是立即报错。
418
421
  """
419
422
  session = self.get_session(session_id)
420
423
  if not session:
421
424
  return {"success": False, "error": f"Session {session_id} not found or expired"}
425
+
426
+ # [v1.20.9] 等待面板打开(最多 15 秒)
422
427
  if not session.is_panel_open:
423
- return {"success": False, "error": "Panel is not open. Use 'open' action first."}
428
+ logger.info(f"[WebControl] 等待面板打开 (session: {session_id}, action: {action})")
429
+ waited = 0
430
+ while waited < 15:
431
+ await asyncio.sleep(1)
432
+ waited += 1
433
+ if session.is_panel_open:
434
+ logger.info(f"[WebControl] 面板已打开 (等待了 {waited}s)")
435
+ break
436
+ # 检查会话是否已关闭
437
+ if session._closed:
438
+ return {"success": False, "error": "Session closed while waiting for panel"}
439
+
440
+ if not session.is_panel_open:
441
+ return {"success": False, "error": "Panel is not open. Use 'open' action first. (waited 15s)"}
424
442
 
425
443
  cmd_id = uuid.uuid4().hex[:10]
426
444
  command = {
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+
3
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports["default"] = void 0;
8
+ var Log = _interopRequireWildcard(require("./util/logging.js"));
9
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
10
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }
11
+ /* This Source Code Form is subject to the terms of the Mozilla Public
12
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
13
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
14
+ // From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools/jint/sunspider/string-base64.js
15
+ var _default = exports["default"] = {
16
+ /* Convert data (an array of integers) to a Base64 string. */
17
+ toBase64Table: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
18
+ base64Pad: '=',
19
+ encode: function encode(data) {
20
+ "use strict";
21
+
22
+ var result = '';
23
+ var length = data.length;
24
+ var lengthpad = length % 3;
25
+ // Convert every three bytes to 4 ascii characters.
26
+
27
+ for (var i = 0; i < length - 2; i += 3) {
28
+ result += this.toBase64Table[data[i] >> 2];
29
+ result += this.toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
30
+ result += this.toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
31
+ result += this.toBase64Table[data[i + 2] & 0x3f];
32
+ }
33
+
34
+ // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
35
+ var j = length - lengthpad;
36
+ if (lengthpad === 2) {
37
+ result += this.toBase64Table[data[j] >> 2];
38
+ result += this.toBase64Table[((data[j] & 0x03) << 4) + (data[j + 1] >> 4)];
39
+ result += this.toBase64Table[(data[j + 1] & 0x0f) << 2];
40
+ result += this.toBase64Table[64];
41
+ } else if (lengthpad === 1) {
42
+ result += this.toBase64Table[data[j] >> 2];
43
+ result += this.toBase64Table[(data[j] & 0x03) << 4];
44
+ result += this.toBase64Table[64];
45
+ result += this.toBase64Table[64];
46
+ }
47
+ return result;
48
+ },
49
+ /* Convert Base64 data to a string */
50
+ /* eslint-disable comma-spacing */
51
+ toBinaryTable: [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1],
52
+ /* eslint-enable comma-spacing */decode: function decode(data) {
53
+ var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
54
+ var dataLength = data.indexOf('=') - offset;
55
+ if (dataLength < 0) {
56
+ dataLength = data.length - offset;
57
+ }
58
+
59
+ /* Every four characters is 3 resulting numbers */
60
+ var resultLength = (dataLength >> 2) * 3 + Math.floor(dataLength % 4 / 1.5);
61
+ var result = new Array(resultLength);
62
+
63
+ // Convert one by one.
64
+
65
+ var leftbits = 0; // number of bits decoded, but yet to be appended
66
+ var leftdata = 0; // bits decoded, but yet to be appended
67
+ for (var idx = 0, i = offset; i < data.length; i++) {
68
+ var c = this.toBinaryTable[data.charCodeAt(i) & 0x7f];
69
+ var padding = data.charAt(i) === this.base64Pad;
70
+ // Skip illegal characters and whitespace
71
+ if (c === -1) {
72
+ Log.Error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
73
+ continue;
74
+ }
75
+
76
+ // Collect data into leftdata, update bitcount
77
+ leftdata = leftdata << 6 | c;
78
+ leftbits += 6;
79
+
80
+ // If we have 8 or more bits, append 8 bits to the result
81
+ if (leftbits >= 8) {
82
+ leftbits -= 8;
83
+ // Append if not padding.
84
+ if (!padding) {
85
+ result[idx++] = leftdata >> leftbits & 0xff;
86
+ }
87
+ leftdata &= (1 << leftbits) - 1;
88
+ }
89
+ }
90
+
91
+ // If there are any bits left, the base64 string was corrupted
92
+ if (leftbits) {
93
+ var err = new Error('Corrupted base64 string');
94
+ err.name = 'Base64-Error';
95
+ throw err;
96
+ }
97
+ return result;
98
+ }
99
+ };
100
+ /* End of Base64 namespace */