liangzimixin 0.3.95 → 0.3.96

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/dist/index.cjs CHANGED
@@ -31480,8 +31480,9 @@ function buildInboundPayload(msg, resolvedContent, config2) {
31480
31480
  // ── 消息标识 ──
31481
31481
  MessageSid: msg.messageId,
31482
31482
  Timestamp: msg.timestamp ?? Date.now(),
31483
- // ── 权限控制 ──
31484
- CommandAuthorized: true
31483
+ // ── 权限控制 (开放给第三方渠道的调用权) ──
31484
+ CommandAuthorized: true,
31485
+ OwnerAllowFrom: [msg.senderId, channelAddress(msg.senderId)]
31485
31486
  };
31486
31487
  if (msg.replyToMessageId) {
31487
31488
  payload.ReplyToId = msg.replyToMessageId;
@@ -31528,19 +31529,27 @@ function createQuantumImDeliverFn(deps) {
31528
31529
  const hasMedia = mediaUrls.length > 0;
31529
31530
  if (!hasText && !hasMedia) return;
31530
31531
  if (hasText) {
31532
+ let textToSend = payload.text;
31533
+ if (isInternalErrorMessage(textToSend)) {
31534
+ log14.warn("\u26A0\uFE0F \u62E6\u622A\u5230 AI \u5185\u90E8\u9519\u8BEF\u6D88\u606F\uFF0C\u66FF\u6362\u4E3A\u53CB\u597D\u63D0\u793A", {
31535
+ chatId,
31536
+ \u539F\u59CB\u5185\u5BB9: textToSend.slice(0, 200)
31537
+ });
31538
+ textToSend = "\u62B1\u6B49\uFF0C\u5904\u7406\u65F6\u95F4\u8F83\u957F\u672A\u80FD\u5B8C\u6210\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5 \u{1F64F}";
31539
+ }
31531
31540
  try {
31532
31541
  await messagePipe.sendMessage({
31533
31542
  chatId,
31534
31543
  senderId,
31535
- msgType: resolveTextMsgType(payload.text),
31536
- content: JSON.stringify({ content: payload.text }),
31544
+ msgType: resolveTextMsgType(textToSend),
31545
+ content: JSON.stringify({ content: textToSend }),
31537
31546
  replyToMessageId,
31538
31547
  skipEncrypt: shouldSkipEncrypt
31539
31548
  });
31540
31549
  log14.info("\u{1F4E4} AI \u6587\u672C\u56DE\u590D\u5DF2\u53D1\u9001", {
31541
31550
  chatId,
31542
- \u957F\u5EA6: payload.text.length,
31543
- \u56DE\u590D\u9884\u89C8: payload.text.slice(0, 200)
31551
+ \u957F\u5EA6: textToSend.length,
31552
+ \u56DE\u590D\u9884\u89C8: textToSend.slice(0, 200)
31544
31553
  });
31545
31554
  } catch (err) {
31546
31555
  log14.error("\u{1F4E4} AI \u6587\u672C\u56DE\u590D\u53D1\u9001\u5931\u8D25", {
@@ -31593,6 +31602,14 @@ function createQuantumImDeliverFn(deps) {
31593
31602
  };
31594
31603
  return { deliver };
31595
31604
  }
31605
+ function isInternalErrorMessage(text) {
31606
+ const trimmed = text.trim();
31607
+ if (trimmed.includes("Request timed out before a response was generated")) return true;
31608
+ if (trimmed.includes("timeoutSeconds") && trimmed.includes("config")) return true;
31609
+ if (trimmed.startsWith("Error:") && trimmed.length < 500) return true;
31610
+ if (trimmed.includes("ETIMEDOUT") || trimmed.includes("ECONNRESET")) return true;
31611
+ return false;
31612
+ }
31596
31613
 
31597
31614
  // src/runtime.ts
31598
31615
  var runtime = null;
@@ -31831,11 +31848,32 @@ var InboundPipeline = class {
31831
31848
  }
31832
31849
  metrics.recordLatency("inbound.ai_reply", Date.now() - aiStartMs);
31833
31850
  const aiDurationMs = Date.now() - aiStartMs;
31851
+ const replyCount = counts?.final ?? 0;
31834
31852
  const durationMs = Date.now() - startMs;
31853
+ if (replyCount === 0) {
31854
+ log15.warn("\u26A0\uFE0F AI \u8FD4\u56DE\u7A7A\u56DE\u590D (\u56DE\u590D\u6570=0)\uFF0C\u53D1\u9001\u53CB\u597D\u63D0\u793A", {
31855
+ messageId: msg.messageId,
31856
+ chatId: msg.chatId,
31857
+ AI\u56DE\u590Dms: aiDurationMs
31858
+ });
31859
+ metrics.increment("inbound.empty_reply");
31860
+ const emptyReplyTip = "\u62B1\u6B49\uFF0C\u6211\u6682\u65F6\u65E0\u6CD5\u56DE\u590D\u8FD9\u6761\u6D88\u606F\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u6216\u6362\u4E2A\u65B9\u5F0F\u63D0\u95EE \u{1F64F}";
31861
+ const emptyReplySkipEncrypt = this.deps.pluginConfig.credentials.encryptionMode === "quantum_only" ? false : true;
31862
+ await this.deps.messagePipe.sendMessage({
31863
+ chatId: msg.chatId,
31864
+ senderId: msg.senderId,
31865
+ msgType: resolveTextMsgType(emptyReplyTip),
31866
+ content: JSON.stringify({ content: emptyReplyTip }),
31867
+ replyToMessageId: msg.messageId,
31868
+ skipEncrypt: emptyReplySkipEncrypt
31869
+ }).catch((tipErr) => {
31870
+ log15.warn("\u26A0\uFE0F \u7A7A\u56DE\u590D\u63D0\u793A\u53D1\u9001\u5931\u8D25", { error: tipErr.message });
31871
+ });
31872
+ }
31835
31873
  log15.info("\u2705 \u6D88\u606F\u5904\u7406\u5B8C\u6210", {
31836
31874
  messageId: msg.messageId,
31837
31875
  chatId: msg.chatId,
31838
- \u56DE\u590D\u6570: counts?.final ?? 0,
31876
+ \u56DE\u590D\u6570: replyCount,
31839
31877
  \u8017\u65F6ms: durationMs,
31840
31878
  AI\u56DE\u590Dms: aiDurationMs,
31841
31879
  \u63D2\u4EF6\u5904\u7406ms: durationMs - aiDurationMs
@@ -32122,8 +32160,8 @@ var quantumImPlugin = {
32122
32160
  // 不支持投票
32123
32161
  nativeCommands: true,
32124
32162
  // 支持 /reset, /new, /help 等原生命令
32125
- blockStreaming: false
32126
- // 不支持块级流式输出
32163
+ blockStreaming: true
32164
+ // 启用块级流式输出,AI 边生成边发送
32127
32165
  },
32128
32166
  agentPrompt: {
32129
32167
  messageToolHints: () => [
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "liangzimixin",
3
- "version": "0.3.95",
3
+ "version": "0.3.96",
4
4
  "description": "Quantum-encrypted IM channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "index.cjs",
@@ -33955,8 +33955,9 @@ function buildInboundPayload(msg, resolvedContent, config2) {
33955
33955
  // ── 消息标识 ──
33956
33956
  MessageSid: msg.messageId,
33957
33957
  Timestamp: msg.timestamp ?? Date.now(),
33958
- // ── 权限控制 ──
33959
- CommandAuthorized: true
33958
+ // ── 权限控制 (开放给第三方渠道的调用权) ──
33959
+ CommandAuthorized: true,
33960
+ OwnerAllowFrom: [msg.senderId, channelAddress(msg.senderId)]
33960
33961
  };
33961
33962
  if (msg.replyToMessageId) {
33962
33963
  payload.ReplyToId = msg.replyToMessageId;
@@ -34003,19 +34004,27 @@ function createQuantumImDeliverFn(deps) {
34003
34004
  const hasMedia = mediaUrls.length > 0;
34004
34005
  if (!hasText && !hasMedia) return;
34005
34006
  if (hasText) {
34007
+ let textToSend = payload.text;
34008
+ if (isInternalErrorMessage(textToSend)) {
34009
+ log27.warn("\u26A0\uFE0F \u62E6\u622A\u5230 AI \u5185\u90E8\u9519\u8BEF\u6D88\u606F\uFF0C\u66FF\u6362\u4E3A\u53CB\u597D\u63D0\u793A", {
34010
+ chatId,
34011
+ \u539F\u59CB\u5185\u5BB9: textToSend.slice(0, 200)
34012
+ });
34013
+ textToSend = "\u62B1\u6B49\uFF0C\u5904\u7406\u65F6\u95F4\u8F83\u957F\u672A\u80FD\u5B8C\u6210\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5 \u{1F64F}";
34014
+ }
34006
34015
  try {
34007
34016
  await messagePipe.sendMessage({
34008
34017
  chatId,
34009
34018
  senderId,
34010
- msgType: resolveTextMsgType(payload.text),
34011
- content: JSON.stringify({ content: payload.text }),
34019
+ msgType: resolveTextMsgType(textToSend),
34020
+ content: JSON.stringify({ content: textToSend }),
34012
34021
  replyToMessageId,
34013
34022
  skipEncrypt: shouldSkipEncrypt
34014
34023
  });
34015
34024
  log27.info("\u{1F4E4} AI \u6587\u672C\u56DE\u590D\u5DF2\u53D1\u9001", {
34016
34025
  chatId,
34017
- \u957F\u5EA6: payload.text.length,
34018
- \u56DE\u590D\u9884\u89C8: payload.text.slice(0, 200)
34026
+ \u957F\u5EA6: textToSend.length,
34027
+ \u56DE\u590D\u9884\u89C8: textToSend.slice(0, 200)
34019
34028
  });
34020
34029
  } catch (err) {
34021
34030
  log27.error("\u{1F4E4} AI \u6587\u672C\u56DE\u590D\u53D1\u9001\u5931\u8D25", {
@@ -34068,6 +34077,14 @@ function createQuantumImDeliverFn(deps) {
34068
34077
  };
34069
34078
  return { deliver };
34070
34079
  }
34080
+ function isInternalErrorMessage(text) {
34081
+ const trimmed = text.trim();
34082
+ if (trimmed.includes("Request timed out before a response was generated")) return true;
34083
+ if (trimmed.includes("timeoutSeconds") && trimmed.includes("config")) return true;
34084
+ if (trimmed.startsWith("Error:") && trimmed.length < 500) return true;
34085
+ if (trimmed.includes("ETIMEDOUT") || trimmed.includes("ECONNRESET")) return true;
34086
+ return false;
34087
+ }
34071
34088
 
34072
34089
  // src/message-handler/handler.ts
34073
34090
  var log28 = createLogger("message-handler/handler");
@@ -34294,11 +34311,32 @@ var InboundPipeline = class {
34294
34311
  }
34295
34312
  metrics.recordLatency("inbound.ai_reply", Date.now() - aiStartMs);
34296
34313
  const aiDurationMs = Date.now() - aiStartMs;
34314
+ const replyCount = counts?.final ?? 0;
34297
34315
  const durationMs = Date.now() - startMs;
34316
+ if (replyCount === 0) {
34317
+ log28.warn("\u26A0\uFE0F AI \u8FD4\u56DE\u7A7A\u56DE\u590D (\u56DE\u590D\u6570=0)\uFF0C\u53D1\u9001\u53CB\u597D\u63D0\u793A", {
34318
+ messageId: msg.messageId,
34319
+ chatId: msg.chatId,
34320
+ AI\u56DE\u590Dms: aiDurationMs
34321
+ });
34322
+ metrics.increment("inbound.empty_reply");
34323
+ const emptyReplyTip = "\u62B1\u6B49\uFF0C\u6211\u6682\u65F6\u65E0\u6CD5\u56DE\u590D\u8FD9\u6761\u6D88\u606F\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u6216\u6362\u4E2A\u65B9\u5F0F\u63D0\u95EE \u{1F64F}";
34324
+ const emptyReplySkipEncrypt = this.deps.pluginConfig.credentials.encryptionMode === "quantum_only" ? false : true;
34325
+ await this.deps.messagePipe.sendMessage({
34326
+ chatId: msg.chatId,
34327
+ senderId: msg.senderId,
34328
+ msgType: resolveTextMsgType(emptyReplyTip),
34329
+ content: JSON.stringify({ content: emptyReplyTip }),
34330
+ replyToMessageId: msg.messageId,
34331
+ skipEncrypt: emptyReplySkipEncrypt
34332
+ }).catch((tipErr) => {
34333
+ log28.warn("\u26A0\uFE0F \u7A7A\u56DE\u590D\u63D0\u793A\u53D1\u9001\u5931\u8D25", { error: tipErr.message });
34334
+ });
34335
+ }
34298
34336
  log28.info("\u2705 \u6D88\u606F\u5904\u7406\u5B8C\u6210", {
34299
34337
  messageId: msg.messageId,
34300
34338
  chatId: msg.chatId,
34301
- \u56DE\u590D\u6570: counts?.final ?? 0,
34339
+ \u56DE\u590D\u6570: replyCount,
34302
34340
  \u8017\u65F6ms: durationMs,
34303
34341
  AI\u56DE\u590Dms: aiDurationMs,
34304
34342
  \u63D2\u4EF6\u5904\u7406ms: durationMs - aiDurationMs
@@ -34517,8 +34555,8 @@ var quantumImPlugin = {
34517
34555
  // 不支持投票
34518
34556
  nativeCommands: true,
34519
34557
  // 支持 /reset, /new, /help 等原生命令
34520
- blockStreaming: false
34521
- // 不支持块级流式输出
34558
+ blockStreaming: true
34559
+ // 启用块级流式输出,AI 边生成边发送
34522
34560
  },
34523
34561
  agentPrompt: {
34524
34562
  messageToolHints: () => [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "liangzimixin",
3
- "version": "0.3.95",
3
+ "version": "0.3.96",
4
4
  "description": "Quantum-encrypted IM channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -18,7 +18,7 @@ REM liangzimixin install script (Windows)
18
18
  REM Usage: liangzimixin_install.bat <appId> <appSecret> [quantumAccount]
19
19
  REM ============================================================
20
20
 
21
- set "SCRIPT_VERSION=0.3.95"
21
+ set "SCRIPT_VERSION=0.3.96"
22
22
  set "NPM_PACKAGE=liangzimixin"
23
23
 
24
24
  set "SKIP_SELF_UPDATE=0"
@@ -229,7 +229,8 @@ set "HEALTH_OK=0"
229
229
  for /l %%i in (1,1,%MAX_RETRIES%) do (
230
230
  if !HEALTH_OK!==0 (
231
231
  echo [INFO] Waiting for service ^(%RETRY_INTERVAL%s^)...
232
- timeout /t %RETRY_INTERVAL% /nobreak >nul
232
+ REM Use ping instead of timeout (timeout requires stdin, fails in non-interactive mode)
233
+ ping -n 6 127.0.0.1 >nul
233
234
 
234
235
  echo [INFO] Check %%i/%MAX_RETRIES%...
235
236
 
@@ -14,7 +14,7 @@ echo -e "\033[0;36m▸\033[0m Deployment log will be saved to $LOG_FILE"
14
14
  # 用法: ./liangzimixin_install.sh <appId> <appSecret> [quantumAccount]
15
15
  # ============================================================
16
16
 
17
- SCRIPT_VERSION="0.3.95"
17
+ SCRIPT_VERSION="0.3.96"
18
18
  NPM_PACKAGE="liangzimixin"
19
19
 
20
20
  # ── 颜色 ──────────────────────────────────────────────────────