liangzimixin 0.3.21 → 0.3.23

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
@@ -18078,6 +18078,10 @@ var tokenManagerGetter = null;
18078
18078
  function setTokenManagerGetter(getter) {
18079
18079
  tokenManagerGetter = getter;
18080
18080
  }
18081
+ var pluginConfigGetter = null;
18082
+ function setPluginConfigGetter(getter) {
18083
+ pluginConfigGetter = getter;
18084
+ }
18081
18085
  var quantumImOutbound = {
18082
18086
  /** 发送模式: 'direct' 表示直接发送,不经过队列 */
18083
18087
  deliveryMode: "direct",
@@ -18105,26 +18109,26 @@ var quantumImOutbound = {
18105
18109
  /** 发送媒体消息 — SDK fetchRemoteMedia + 三步上传 + 发送 */
18106
18110
  sendMedia: async ({ cfg, to, text, mediaUrl, mediaLocalRoots, accountId }) => {
18107
18111
  log4.info("sendMedia called", { to, mediaUrl });
18108
- if (!messagePipeGetter || !sdkRuntimeGetter || !tokenManagerGetter) {
18112
+ if (!messagePipeGetter || !sdkRuntimeGetter || !tokenManagerGetter || !pluginConfigGetter) {
18109
18113
  log4.error("outbound:sendMedia failed, dependencies not initialized");
18110
18114
  return { channel: CHANNEL_ID, messageId: "", chatId: to };
18111
18115
  }
18112
18116
  const messagePipe = messagePipeGetter();
18113
18117
  const sdkRuntime = sdkRuntimeGetter();
18114
18118
  const chatId = parseChannelAddress(to);
18115
- const fileCfg = cfg?.channels?.[CHANNEL_ID]?.file;
18119
+ const fileCfg = pluginConfigGetter().file;
18116
18120
  const result = await resolveAndUploadMedia({
18117
18121
  mediaUrl: mediaUrl ?? void 0,
18118
18122
  tokenManager: tokenManagerGetter(),
18119
- serverUrl: fileCfg?.fileServiceBaseUrl ?? "",
18123
+ serverUrl: fileCfg.fileServiceBaseUrl,
18120
18124
  allowedLocalRoots: mediaLocalRoots ?? void 0,
18121
- allowPrivateNetwork: fileCfg?.allowPrivateNetwork ?? false,
18125
+ allowPrivateNetwork: fileCfg.allowPrivateNetwork,
18122
18126
  sdkRuntime,
18123
18127
  messagePipe,
18124
18128
  chatId,
18125
- maxFileSizeMb: fileCfg?.maxFileSizeMb,
18126
- chunkSizeMb: fileCfg?.chunkSizeMb,
18127
- timeoutMs: fileCfg?.fetchTimeoutMs
18129
+ maxFileSizeMb: fileCfg.maxFileSizeMb,
18130
+ chunkSizeMb: fileCfg.chunkSizeMb,
18131
+ timeoutMs: fileCfg.fetchTimeoutMs
18128
18132
  });
18129
18133
  if (result.warning) {
18130
18134
  log4.warn("sendMedia:degraded", { chatId, warning: result.warning });
@@ -18412,21 +18416,81 @@ function buildInboundPayload(msg, resolvedContent, config2) {
18412
18416
  // src/reply-dispatcher/dispatcher.ts
18413
18417
  var log11 = createLogger("reply-dispatcher/dispatcher");
18414
18418
  function createQuantumImDeliverFn(deps) {
18415
- const { messagePipe, chatId, senderId, replyToMessageId } = deps;
18419
+ const {
18420
+ messagePipe,
18421
+ chatId,
18422
+ senderId,
18423
+ replyToMessageId,
18424
+ tokenManager,
18425
+ fileServerUrl,
18426
+ sdkRuntimeGetter: sdkRuntimeGetter2,
18427
+ allowedLocalRoots,
18428
+ allowPrivateNetwork = false,
18429
+ maxFileSizeMb,
18430
+ chunkSizeMb,
18431
+ timeoutMs
18432
+ } = deps;
18416
18433
  const deliver = async (payload) => {
18417
- if (!payload.text?.trim()) return;
18418
- await messagePipe.sendMessage({
18419
- chatId,
18420
- senderId,
18421
- msgType: "markdown",
18422
- content: JSON.stringify({ content: payload.text }),
18423
- replyToMessageId
18424
- });
18425
- log11.info("\u{1F4E4} AI \u56DE\u590D\u5DF2\u53D1\u9001", {
18426
- chatId,
18427
- \u957F\u5EA6: payload.text.length,
18428
- \u56DE\u590D\u9884\u89C8: payload.text.slice(0, 200)
18429
- });
18434
+ const mediaUrls = [];
18435
+ if (payload.mediaUrls?.length) {
18436
+ mediaUrls.push(...payload.mediaUrls);
18437
+ } else if (payload.mediaUrl) {
18438
+ mediaUrls.push(payload.mediaUrl);
18439
+ }
18440
+ const hasText = Boolean(payload.text?.trim());
18441
+ const hasMedia = mediaUrls.length > 0;
18442
+ if (!hasText && !hasMedia) return;
18443
+ if (hasText) {
18444
+ await messagePipe.sendMessage({
18445
+ chatId,
18446
+ senderId,
18447
+ msgType: "markdown",
18448
+ content: JSON.stringify({ content: payload.text }),
18449
+ replyToMessageId
18450
+ });
18451
+ log11.info("\u{1F4E4} AI \u6587\u672C\u56DE\u590D\u5DF2\u53D1\u9001", {
18452
+ chatId,
18453
+ \u957F\u5EA6: payload.text.length,
18454
+ \u56DE\u590D\u9884\u89C8: payload.text.slice(0, 200)
18455
+ });
18456
+ }
18457
+ if (hasMedia) {
18458
+ for (const mediaUrl of mediaUrls) {
18459
+ try {
18460
+ const result = await resolveAndUploadMedia({
18461
+ mediaUrl,
18462
+ tokenManager,
18463
+ serverUrl: fileServerUrl,
18464
+ allowedLocalRoots,
18465
+ allowPrivateNetwork,
18466
+ sdkRuntime: sdkRuntimeGetter2(),
18467
+ messagePipe,
18468
+ chatId,
18469
+ maxFileSizeMb,
18470
+ chunkSizeMb,
18471
+ timeoutMs
18472
+ });
18473
+ if (result.warning) {
18474
+ log11.warn("\u{1F4E4} \u5A92\u4F53\u53D1\u9001\u964D\u7EA7", { chatId, mediaUrl, warning: result.warning });
18475
+ } else {
18476
+ log11.info("\u{1F4E4} \u5A92\u4F53\u6D88\u606F\u5DF2\u53D1\u9001", { chatId, mediaUrl });
18477
+ }
18478
+ } catch (err) {
18479
+ log11.error("\u{1F4E4} \u5A92\u4F53\u53D1\u9001\u5931\u8D25\uFF0C\u964D\u7EA7\u4E3A\u6587\u672C\u94FE\u63A5", {
18480
+ chatId,
18481
+ mediaUrl,
18482
+ error: err.message
18483
+ });
18484
+ await messagePipe.sendMessage({
18485
+ chatId,
18486
+ senderId,
18487
+ msgType: "markdown",
18488
+ content: JSON.stringify({ content: `\u{1F4CE} ${mediaUrl}` }),
18489
+ replyToMessageId
18490
+ });
18491
+ }
18492
+ }
18493
+ }
18430
18494
  };
18431
18495
  return { deliver };
18432
18496
  }
@@ -18475,7 +18539,8 @@ var InboundPipeline = class {
18475
18539
  chatId: msg.chatId,
18476
18540
  senderId: msg.senderId,
18477
18541
  msgType: "markdown",
18478
- content: JSON.stringify({ content: "\u601D\u8003\u4E2D..." })
18542
+ content: JSON.stringify({ content: "\u601D\u8003\u4E2D..." }),
18543
+ skipEncrypt: true
18479
18544
  }).catch((err) => {
18480
18545
  log12.warn('\u26A0\uFE0F "\u601D\u8003\u4E2D"\u53D1\u9001\u5931\u8D25', { error: err.message });
18481
18546
  });
@@ -18495,7 +18560,14 @@ var InboundPipeline = class {
18495
18560
  messagePipe: this.deps.messagePipe,
18496
18561
  chatId: msg.chatId,
18497
18562
  senderId: msg.senderId,
18498
- replyToMessageId: msg.messageId
18563
+ replyToMessageId: msg.messageId,
18564
+ tokenManager: this.deps.tokenManager,
18565
+ fileServerUrl: this.deps.pluginConfig.file.fileServiceBaseUrl,
18566
+ sdkRuntimeGetter: () => getPluginRuntime(),
18567
+ allowedLocalRoots: void 0,
18568
+ allowPrivateNetwork: this.deps.pluginConfig.file.allowPrivateNetwork,
18569
+ maxFileSizeMb: this.deps.pluginConfig.file.maxFileSizeMb,
18570
+ timeoutMs: this.deps.pluginConfig.file.fetchTimeoutMs
18499
18571
  });
18500
18572
  const { dispatcher, replyOptions } = core.channel.reply.createReplyDispatcherWithTyping({
18501
18573
  deliver
@@ -18883,6 +18955,7 @@ var quantumImPlugin = {
18883
18955
  setMessagePipeGetter(() => instance.messagePipe);
18884
18956
  setSdkRuntimeGetter(() => getPluginRuntime());
18885
18957
  setTokenManagerGetter(() => instance.tokenManager);
18958
+ setPluginConfigGetter(() => instance.config);
18886
18959
  log13.info(`liangzimixin[${ctx.accountId}] started \u2713`);
18887
18960
  await new Promise((resolve3) => {
18888
18961
  if (ctx.abortSignal?.aborted) {
@@ -19836,7 +19909,7 @@ var MessagePipe = class {
19836
19909
  async sendMessage(msg) {
19837
19910
  let content = msg.content;
19838
19911
  let extra = "";
19839
- if (this.quantumAccount) {
19912
+ if (this.quantumAccount && !msg.skipEncrypt) {
19840
19913
  try {
19841
19914
  const { ciphertext, keyId, iv } = await this.crypto.encrypt(msg.content);
19842
19915
  extra = JSON.stringify({
package/dist/index.d.cts CHANGED
@@ -181,6 +181,8 @@ interface OutboundMessage {
181
181
  content: string;
182
182
  /** 回复的原消息 ID */
183
183
  replyToMessageId?: string;
184
+ /** 跳过出站加密 — 用于"思考中"等无需加密的系统提示消息 */
185
+ skipEncrypt?: boolean;
184
186
  }
185
187
  /**
186
188
  * 加密策略枚举 — 根据消息类型选择不同的加密等级
@@ -4173,6 +4173,10 @@ var tokenManagerGetter = null;
4173
4173
  function setTokenManagerGetter(getter) {
4174
4174
  tokenManagerGetter = getter;
4175
4175
  }
4176
+ var pluginConfigGetter = null;
4177
+ function setPluginConfigGetter(getter) {
4178
+ pluginConfigGetter = getter;
4179
+ }
4176
4180
  var quantumImOutbound = {
4177
4181
  /** 发送模式: 'direct' 表示直接发送,不经过队列 */
4178
4182
  deliveryMode: "direct",
@@ -4200,26 +4204,26 @@ var quantumImOutbound = {
4200
4204
  /** 发送媒体消息 — SDK fetchRemoteMedia + 三步上传 + 发送 */
4201
4205
  sendMedia: async ({ cfg, to, text, mediaUrl, mediaLocalRoots, accountId }) => {
4202
4206
  log4.info("sendMedia called", { to, mediaUrl });
4203
- if (!messagePipeGetter || !sdkRuntimeGetter || !tokenManagerGetter) {
4207
+ if (!messagePipeGetter || !sdkRuntimeGetter || !tokenManagerGetter || !pluginConfigGetter) {
4204
4208
  log4.error("outbound:sendMedia failed, dependencies not initialized");
4205
4209
  return { channel: CHANNEL_ID, messageId: "", chatId: to };
4206
4210
  }
4207
4211
  const messagePipe = messagePipeGetter();
4208
4212
  const sdkRuntime = sdkRuntimeGetter();
4209
4213
  const chatId = parseChannelAddress(to);
4210
- const fileCfg = cfg?.channels?.[CHANNEL_ID]?.file;
4214
+ const fileCfg = pluginConfigGetter().file;
4211
4215
  const result = await resolveAndUploadMedia({
4212
4216
  mediaUrl: mediaUrl ?? void 0,
4213
4217
  tokenManager: tokenManagerGetter(),
4214
- serverUrl: fileCfg?.fileServiceBaseUrl ?? "",
4218
+ serverUrl: fileCfg.fileServiceBaseUrl,
4215
4219
  allowedLocalRoots: mediaLocalRoots ?? void 0,
4216
- allowPrivateNetwork: fileCfg?.allowPrivateNetwork ?? false,
4220
+ allowPrivateNetwork: fileCfg.allowPrivateNetwork,
4217
4221
  sdkRuntime,
4218
4222
  messagePipe,
4219
4223
  chatId,
4220
- maxFileSizeMb: fileCfg?.maxFileSizeMb,
4221
- chunkSizeMb: fileCfg?.chunkSizeMb,
4222
- timeoutMs: fileCfg?.fetchTimeoutMs
4224
+ maxFileSizeMb: fileCfg.maxFileSizeMb,
4225
+ chunkSizeMb: fileCfg.chunkSizeMb,
4226
+ timeoutMs: fileCfg.fetchTimeoutMs
4223
4227
  });
4224
4228
  if (result.warning) {
4225
4229
  log4.warn("sendMedia:degraded", { chatId, warning: result.warning });
@@ -19040,7 +19044,7 @@ var MessagePipe = class {
19040
19044
  async sendMessage(msg) {
19041
19045
  let content = msg.content;
19042
19046
  let extra = "";
19043
- if (this.quantumAccount) {
19047
+ if (this.quantumAccount && !msg.skipEncrypt) {
19044
19048
  try {
19045
19049
  const { ciphertext, keyId, iv } = await this.crypto.encrypt(msg.content);
19046
19050
  extra = JSON.stringify({
@@ -20213,21 +20217,81 @@ function buildInboundPayload(msg, resolvedContent, config2) {
20213
20217
  // src/reply-dispatcher/dispatcher.ts
20214
20218
  var log23 = createLogger("reply-dispatcher/dispatcher");
20215
20219
  function createQuantumImDeliverFn(deps) {
20216
- const { messagePipe, chatId, senderId, replyToMessageId } = deps;
20220
+ const {
20221
+ messagePipe,
20222
+ chatId,
20223
+ senderId,
20224
+ replyToMessageId,
20225
+ tokenManager,
20226
+ fileServerUrl,
20227
+ sdkRuntimeGetter: sdkRuntimeGetter2,
20228
+ allowedLocalRoots,
20229
+ allowPrivateNetwork = false,
20230
+ maxFileSizeMb,
20231
+ chunkSizeMb,
20232
+ timeoutMs
20233
+ } = deps;
20217
20234
  const deliver = async (payload) => {
20218
- if (!payload.text?.trim()) return;
20219
- await messagePipe.sendMessage({
20220
- chatId,
20221
- senderId,
20222
- msgType: "markdown",
20223
- content: JSON.stringify({ content: payload.text }),
20224
- replyToMessageId
20225
- });
20226
- log23.info("\u{1F4E4} AI \u56DE\u590D\u5DF2\u53D1\u9001", {
20227
- chatId,
20228
- \u957F\u5EA6: payload.text.length,
20229
- \u56DE\u590D\u9884\u89C8: payload.text.slice(0, 200)
20230
- });
20235
+ const mediaUrls = [];
20236
+ if (payload.mediaUrls?.length) {
20237
+ mediaUrls.push(...payload.mediaUrls);
20238
+ } else if (payload.mediaUrl) {
20239
+ mediaUrls.push(payload.mediaUrl);
20240
+ }
20241
+ const hasText = Boolean(payload.text?.trim());
20242
+ const hasMedia = mediaUrls.length > 0;
20243
+ if (!hasText && !hasMedia) return;
20244
+ if (hasText) {
20245
+ await messagePipe.sendMessage({
20246
+ chatId,
20247
+ senderId,
20248
+ msgType: "markdown",
20249
+ content: JSON.stringify({ content: payload.text }),
20250
+ replyToMessageId
20251
+ });
20252
+ log23.info("\u{1F4E4} AI \u6587\u672C\u56DE\u590D\u5DF2\u53D1\u9001", {
20253
+ chatId,
20254
+ \u957F\u5EA6: payload.text.length,
20255
+ \u56DE\u590D\u9884\u89C8: payload.text.slice(0, 200)
20256
+ });
20257
+ }
20258
+ if (hasMedia) {
20259
+ for (const mediaUrl of mediaUrls) {
20260
+ try {
20261
+ const result = await resolveAndUploadMedia({
20262
+ mediaUrl,
20263
+ tokenManager,
20264
+ serverUrl: fileServerUrl,
20265
+ allowedLocalRoots,
20266
+ allowPrivateNetwork,
20267
+ sdkRuntime: sdkRuntimeGetter2(),
20268
+ messagePipe,
20269
+ chatId,
20270
+ maxFileSizeMb,
20271
+ chunkSizeMb,
20272
+ timeoutMs
20273
+ });
20274
+ if (result.warning) {
20275
+ log23.warn("\u{1F4E4} \u5A92\u4F53\u53D1\u9001\u964D\u7EA7", { chatId, mediaUrl, warning: result.warning });
20276
+ } else {
20277
+ log23.info("\u{1F4E4} \u5A92\u4F53\u6D88\u606F\u5DF2\u53D1\u9001", { chatId, mediaUrl });
20278
+ }
20279
+ } catch (err) {
20280
+ log23.error("\u{1F4E4} \u5A92\u4F53\u53D1\u9001\u5931\u8D25\uFF0C\u964D\u7EA7\u4E3A\u6587\u672C\u94FE\u63A5", {
20281
+ chatId,
20282
+ mediaUrl,
20283
+ error: err.message
20284
+ });
20285
+ await messagePipe.sendMessage({
20286
+ chatId,
20287
+ senderId,
20288
+ msgType: "markdown",
20289
+ content: JSON.stringify({ content: `\u{1F4CE} ${mediaUrl}` }),
20290
+ replyToMessageId
20291
+ });
20292
+ }
20293
+ }
20294
+ }
20231
20295
  };
20232
20296
  return { deliver };
20233
20297
  }
@@ -20264,7 +20328,8 @@ var InboundPipeline = class {
20264
20328
  chatId: msg.chatId,
20265
20329
  senderId: msg.senderId,
20266
20330
  msgType: "markdown",
20267
- content: JSON.stringify({ content: "\u601D\u8003\u4E2D..." })
20331
+ content: JSON.stringify({ content: "\u601D\u8003\u4E2D..." }),
20332
+ skipEncrypt: true
20268
20333
  }).catch((err) => {
20269
20334
  log24.warn('\u26A0\uFE0F "\u601D\u8003\u4E2D"\u53D1\u9001\u5931\u8D25', { error: err.message });
20270
20335
  });
@@ -20284,7 +20349,14 @@ var InboundPipeline = class {
20284
20349
  messagePipe: this.deps.messagePipe,
20285
20350
  chatId: msg.chatId,
20286
20351
  senderId: msg.senderId,
20287
- replyToMessageId: msg.messageId
20352
+ replyToMessageId: msg.messageId,
20353
+ tokenManager: this.deps.tokenManager,
20354
+ fileServerUrl: this.deps.pluginConfig.file.fileServiceBaseUrl,
20355
+ sdkRuntimeGetter: () => getPluginRuntime(),
20356
+ allowedLocalRoots: void 0,
20357
+ allowPrivateNetwork: this.deps.pluginConfig.file.allowPrivateNetwork,
20358
+ maxFileSizeMb: this.deps.pluginConfig.file.maxFileSizeMb,
20359
+ timeoutMs: this.deps.pluginConfig.file.fetchTimeoutMs
20288
20360
  });
20289
20361
  const { dispatcher, replyOptions } = core.channel.reply.createReplyDispatcherWithTyping({
20290
20362
  deliver
@@ -20611,6 +20683,7 @@ var quantumImPlugin = {
20611
20683
  setMessagePipeGetter(() => instance.messagePipe);
20612
20684
  setSdkRuntimeGetter(() => getPluginRuntime());
20613
20685
  setTokenManagerGetter(() => instance.tokenManager);
20686
+ setPluginConfigGetter(() => instance.config);
20614
20687
  log25.info(`liangzimixin[${ctx.accountId}] started \u2713`);
20615
20688
  await new Promise((resolve3) => {
20616
20689
  if (ctx.abortSignal?.aborted) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "liangzimixin",
3
- "version": "0.3.21",
3
+ "version": "0.3.23",
4
4
  "description": "Quantum-encrypted IM channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",