@xmanrui/dsh-im 0.17.0 → 0.18.0

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 (49) hide show
  1. package/README.en.md +3 -2
  2. package/README.md +3 -2
  3. package/lib/client.js +964 -538
  4. package/lib/index.js +189 -144
  5. package/package.json +1 -1
  6. package/plugin-src/client/agent-preset.js +110 -0
  7. package/plugin-src/client/channels/dingtalk/api.js +5 -0
  8. package/plugin-src/client/channels/dingtalk/index.js +48 -2
  9. package/plugin-src/client/channels/feishu/api.js +5 -0
  10. package/plugin-src/client/channels/feishu/index.js +39 -2
  11. package/plugin-src/client/channels/qq/api.js +5 -0
  12. package/plugin-src/client/channels/qq/index.js +37 -6
  13. package/plugin-src/client/channels/shared/token-api.js +5 -0
  14. package/plugin-src/client/channels/shared/token-channel.js +34 -6
  15. package/plugin-src/client/channels/wecom/api.js +5 -0
  16. package/plugin-src/client/channels/wecom/index.js +37 -6
  17. package/plugin-src/client/channels/weixin/api.js +15 -0
  18. package/plugin-src/client/channels/weixin/index.js +54 -4
  19. package/plugin-src/client/channels/whatsapp/api.js +5 -0
  20. package/plugin-src/client/channels/whatsapp/index.js +30 -4
  21. package/plugin-src/client/i18n.js +29 -0
  22. package/plugin-src/client/styles.js +8 -0
  23. package/plugin-src/host/channels/dingtalk/production.mjs +10 -4
  24. package/plugin-src/host/channels/dingtalk/rpc.mjs +12 -0
  25. package/plugin-src/host/channels/feishu/connection-supervisor.mjs +1 -1
  26. package/plugin-src/host/channels/feishu/production.mjs +6 -3
  27. package/plugin-src/host/channels/feishu/rpc.mjs +17 -0
  28. package/plugin-src/host/channels/qq/production.mjs +10 -4
  29. package/plugin-src/host/channels/qq/rpc.mjs +12 -0
  30. package/plugin-src/host/channels/shared/agent-preset-rpc.mjs +25 -0
  31. package/plugin-src/host/channels/shared/production.mjs +10 -4
  32. package/plugin-src/host/channels/shared/rpc.mjs +12 -0
  33. package/plugin-src/host/channels/shared/workspace-rpc.mjs +2 -0
  34. package/plugin-src/host/channels/slack/production.mjs +10 -4
  35. package/plugin-src/host/channels/slack/rpc.mjs +13 -0
  36. package/plugin-src/host/channels/wecom/production.mjs +10 -4
  37. package/plugin-src/host/channels/wecom/rpc.mjs +12 -0
  38. package/plugin-src/host/channels/weixin/production.mjs +10 -4
  39. package/plugin-src/host/channels/weixin/rpc.mjs +15 -0
  40. package/plugin-src/host/channels/whatsapp/production.mjs +10 -4
  41. package/plugin-src/host/channels/whatsapp/rpc.mjs +12 -0
  42. package/src/channels/discord/discord-api.mjs +1 -1
  43. package/src/channels/shared/agent-preset.mjs +74 -0
  44. package/src/channels/shared/bot-workspace-store.mjs +141 -14
  45. package/src/channels/shared/harness-client.mjs +6 -4
  46. package/src/channels/shared/image-prompt.mjs +32 -1
  47. package/src/channels/weixin/weixin-api.mjs +1 -1
  48. package/src/channels/weixin/weixin-bridge.mjs +23 -3
  49. package/src/channels/weixin/weixin-controller.mjs +15 -0
@@ -23,12 +23,14 @@ import { runWorkspaceCommand } from '../shared/workspace-command.mjs';
23
23
  import { askInWorkspaceSession } from '../shared/workspace-session.mjs';
24
24
  import {
25
25
  hasInboundImages,
26
+ imagePromptDiagnostic,
26
27
  imagePromptUserMessage,
27
28
  promptContentForMessage,
28
29
  } from '../shared/image-prompt.mjs';
29
30
  import { rememberConnectionTestTarget } from '../shared/connection-test.mjs';
30
31
 
31
32
  const INTERACTION_RESOLVED_TEXT = '这个问题已在其他客户端处理,无需再次回答。';
33
+ const GENERIC_PROCESSING_ERROR = '消息处理失败,请稍后重试。';
32
34
 
33
35
  const HELP_TEXT = [
34
36
  '微信已连接 DeepSeek Harness。',
@@ -69,6 +71,16 @@ function canClaimInteractionReply(message, pending) {
69
71
  && nonEmptyString(extractWeixinText(message));
70
72
  }
71
73
 
74
+ function safeMessageError(error, userMessage = GENERIC_PROCESSING_ERROR) {
75
+ const diagnostic = imagePromptDiagnostic(error);
76
+ return {
77
+ code: diagnostic?.code ?? 'message-processing-failed',
78
+ reason: diagnostic?.reason ?? 'UNKNOWN',
79
+ message: diagnostic?.userMessage ?? userMessage,
80
+ at: Date.now(),
81
+ };
82
+ }
83
+
72
84
  export function createWeixinBridgeStatus() {
73
85
  return {
74
86
  messagesReceived: 0,
@@ -78,6 +90,7 @@ export function createWeixinBridgeStatus() {
78
90
  lastReplyAt: null,
79
91
  lastRejectedAt: null,
80
92
  lastError: null,
93
+ lastMessageError: null,
81
94
  };
82
95
  }
83
96
 
@@ -168,8 +181,9 @@ export class WeixinHarnessBridge {
168
181
  ).catch((error) => {
169
182
  if (error?.code === 'turn-stopped' || this.#signal?.aborted) return;
170
183
  this.#status.lastError = error?.message ?? String(error);
184
+ this.#status.lastMessageError = safeMessageError(error);
171
185
  this.#logger.error?.('[dsh-weixin] failed to process a command:', error);
172
- return this.#send(sender, '消息处理失败,请稍后重试。', contextToken, runId)
186
+ return this.#send(sender, GENERIC_PROCESSING_ERROR, contextToken, runId)
173
187
  .catch(() => undefined);
174
188
  }).finally(() => {
175
189
  this.#acceptedMessageIds.delete(messageId);
@@ -289,6 +303,7 @@ export class WeixinHarnessBridge {
289
303
  if (reply) await this.#send(sender, reply, contextToken, runId);
290
304
  }
291
305
  this.#status.lastError = null;
306
+ this.#status.lastMessageError = null;
292
307
  }
293
308
 
294
309
  async #process(message, key, { alreadyRecorded = false } = {}) {
@@ -401,6 +416,7 @@ export class WeixinHarnessBridge {
401
416
  this.#status.messagesReplied += 1;
402
417
  this.#status.lastReplyAt = new Date().toISOString();
403
418
  this.#status.lastError = null;
419
+ this.#status.lastMessageError = null;
404
420
  } catch (error) {
405
421
  if (error?.code === 'turn-stopped') {
406
422
  await this.#state.markSeen(messageId);
@@ -408,11 +424,13 @@ export class WeixinHarnessBridge {
408
424
  }
409
425
  if (this.#signal?.aborted) return;
410
426
  this.#status.lastError = error?.message ?? String(error);
427
+ const userMessage = imagePromptUserMessage(error) ?? GENERIC_PROCESSING_ERROR;
428
+ this.#status.lastMessageError = safeMessageError(error, userMessage);
411
429
  this.#logger.error?.('[dsh-weixin] failed to process an inbound message:', error);
412
430
  try {
413
431
  await this.#send(
414
432
  sender,
415
- imagePromptUserMessage(error) ?? '消息处理失败,请稍后重试。',
433
+ userMessage,
416
434
  contextToken,
417
435
  runId,
418
436
  );
@@ -526,6 +544,7 @@ export class WeixinHarnessBridge {
526
544
  });
527
545
  this.#clearPendingInteraction(key, pending.interactionId);
528
546
  this.#status.lastError = null;
547
+ this.#status.lastMessageError = null;
529
548
  } catch (error) {
530
549
  if (this.#signal?.aborted) return;
531
550
  if (error?.code === 'interaction-not-pending') {
@@ -719,13 +738,14 @@ export class WeixinHarnessBridge {
719
738
  async #handleInteractionFailure(message, messageId, error) {
720
739
  if (this.#signal?.aborted) return;
721
740
  this.#status.lastError = error?.message ?? String(error);
741
+ this.#status.lastMessageError = safeMessageError(error);
722
742
  this.#logger.error?.('[dsh-weixin] failed to process an interaction reply:', error);
723
743
  if (!this.#state.hasSeen(messageId)) {
724
744
  await this.#state.markSeen(messageId).catch(() => undefined);
725
745
  }
726
746
  await this.#send(
727
747
  nonEmptyString(message?.from_user_id),
728
- '消息处理失败,请稍后重试。',
748
+ GENERIC_PROCESSING_ERROR,
729
749
  nonEmptyString(message?.context_token) ?? undefined,
730
750
  nonEmptyString(message?.run_id) ?? undefined,
731
751
  ).catch(() => undefined);
@@ -62,6 +62,20 @@ function safeAccountError(code, message) {
62
62
  return Object.freeze({ code, message });
63
63
  }
64
64
 
65
+ function publicMessageError(value) {
66
+ if (!value || typeof value !== 'object'
67
+ || typeof value.code !== 'string' || !value.code
68
+ || typeof value.reason !== 'string' || !value.reason
69
+ || typeof value.message !== 'string' || !value.message
70
+ || !Number.isFinite(value.at)) return null;
71
+ return {
72
+ code: value.code.slice(0, 64),
73
+ reason: value.reason.slice(0, 128),
74
+ message: value.message.slice(0, 500),
75
+ at: value.at,
76
+ };
77
+ }
78
+
65
79
  function activationStageError(code, cause) {
66
80
  const error = new Error(`Weixin activation failed during ${code}`, { cause });
67
81
  error.name = 'WeixinActivationStageError';
@@ -351,6 +365,7 @@ export class WeixinController {
351
365
  messagesReceived: runtimeStatus?.messagesReceived ?? 0,
352
366
  messagesReplied: runtimeStatus?.messagesReplied ?? 0,
353
367
  },
368
+ lastMessageError: publicMessageError(runtimeStatus?.lastMessageError),
354
369
  error: error ? structuredClone(error) : null,
355
370
  };
356
371
  });