@soimy/dingtalk 3.5.1 → 3.5.2
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/README.md +7 -1
- package/package.json +8 -3
- package/src/ack-reaction-service.ts +1 -1
- package/src/auth.ts +1 -1
- package/src/card/card-action-handler.ts +1 -1
- package/src/card/card-stop-handler.ts +1 -1
- package/src/card/reasoning-block-assembler.ts +157 -0
- package/src/card-callback-service.ts +1 -1
- package/src/card-draft-controller.ts +32 -0
- package/src/card-service.ts +1 -1
- package/src/channel.ts +71 -55
- package/src/command/card-stop-command.ts +4 -22
- package/src/command/inbound-command-dispatch-service.ts +464 -0
- package/src/docs-service.ts +5 -5
- package/src/http-client.ts +20 -0
- package/src/inbound-handler.ts +120 -463
- package/src/logger-context.ts +16 -2
- package/src/media-utils.ts +3 -3
- package/src/{attachment-text-extractor.ts → messaging/attachment-text-extractor.ts} +1 -1
- package/src/{quoted-file-service.ts → messaging/quoted-file-service.ts} +5 -5
- package/src/reply-strategy-card.ts +64 -13
- package/src/reply-strategy-markdown.ts +123 -18
- package/src/reply-strategy.ts +4 -0
- package/src/send-service.ts +68 -3
- package/src/targeting/agent-routing.ts +11 -4
- package/src/{group-members-store.ts → targeting/group-members-store.ts} +1 -1
- package/src/utils.ts +165 -0
package/src/channel.ts
CHANGED
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
recordExplicitFeedbackLearning,
|
|
34
34
|
} from "./feedback-learning-service";
|
|
35
35
|
import { handleDingTalkMessage } from "./inbound-handler";
|
|
36
|
-
import { getLogger } from "./logger-context";
|
|
36
|
+
import { getLogger, setCurrentLogger } from "./logger-context";
|
|
37
37
|
import { prepareMediaInput, resolveOutboundMediaType } from "./media-utils";
|
|
38
38
|
import { dingtalkSetupAdapter, dingtalkSetupWizard } from "./onboarding.js";
|
|
39
39
|
import { resolveOriginalPeerId, preloadPeerIdsFromSessions } from "./peer-id-registry";
|
|
@@ -62,11 +62,13 @@ import type {
|
|
|
62
62
|
} from "./types";
|
|
63
63
|
import { ConnectionState } from "./types";
|
|
64
64
|
import {
|
|
65
|
+
closePluginDebugLog,
|
|
65
66
|
cleanupOrphanedTempFiles,
|
|
66
67
|
createResolve4FallbackLookup,
|
|
67
68
|
formatDingTalkConnectionErrorLog,
|
|
68
69
|
formatDingTalkErrorPayloadLog,
|
|
69
70
|
getCurrentTimestamp,
|
|
71
|
+
resolvePluginDebugLog,
|
|
70
72
|
} from "./utils";
|
|
71
73
|
|
|
72
74
|
type InstrumentedDWClient = {
|
|
@@ -460,14 +462,15 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
460
462
|
const storePath = rt.channel.session.resolveStorePath(cfg.session?.store, {
|
|
461
463
|
agentId: accountId,
|
|
462
464
|
});
|
|
465
|
+
const effectiveLog = getLogger(accountId) || log;
|
|
463
466
|
try {
|
|
464
467
|
const result = await sendMessage(config, to, text, {
|
|
465
|
-
log,
|
|
468
|
+
log: effectiveLog,
|
|
466
469
|
accountId,
|
|
467
470
|
storePath,
|
|
468
471
|
conversationId: to,
|
|
469
472
|
});
|
|
470
|
-
|
|
473
|
+
effectiveLog?.debug?.(`[DingTalk] sendText: "${text}" result: ${JSON.stringify(result)}`);
|
|
471
474
|
if (!result.ok) {
|
|
472
475
|
throw new Error(result.error || "sendText failed");
|
|
473
476
|
}
|
|
@@ -487,7 +490,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
487
490
|
};
|
|
488
491
|
} catch (err: any) {
|
|
489
492
|
if (err?.response?.data !== undefined) {
|
|
490
|
-
|
|
493
|
+
effectiveLog?.error?.(formatDingTalkErrorPayloadLog("outbound.sendText", err.response.data));
|
|
491
494
|
}
|
|
492
495
|
throw new Error(
|
|
493
496
|
typeof err?.response?.data === "string"
|
|
@@ -514,6 +517,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
514
517
|
const storePath = rt.channel.session.resolveStorePath(cfg.session?.store, {
|
|
515
518
|
agentId: accountId,
|
|
516
519
|
});
|
|
520
|
+
const effectiveLog = getLogger(accountId) || log;
|
|
517
521
|
if (!config.clientId) {
|
|
518
522
|
throw new Error("DingTalk not configured");
|
|
519
523
|
}
|
|
@@ -521,7 +525,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
521
525
|
// Support mediaPath/filePath/mediaUrl aliases for better CLI compatibility.
|
|
522
526
|
const rawMediaPath = mediaPath || filePath || mediaUrl;
|
|
523
527
|
|
|
524
|
-
|
|
528
|
+
effectiveLog?.debug?.(
|
|
525
529
|
`[DingTalk] sendMedia called: to=${to}, mediaPath=${mediaPath}, filePath=${filePath}, mediaUrl=${mediaUrl}, rawMediaPath=${rawMediaPath}`,
|
|
526
530
|
);
|
|
527
531
|
|
|
@@ -539,10 +543,10 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
539
543
|
let preparedMedia;
|
|
540
544
|
try {
|
|
541
545
|
try {
|
|
542
|
-
preparedMedia = await prepareMediaInput(rawMediaPath,
|
|
546
|
+
preparedMedia = await prepareMediaInput(rawMediaPath, effectiveLog, config.mediaUrlAllowlist);
|
|
543
547
|
} catch (err: any) {
|
|
544
548
|
if (err?.response?.data !== undefined) {
|
|
545
|
-
|
|
549
|
+
effectiveLog?.error?.(
|
|
546
550
|
formatDingTalkErrorPayloadLog("outbound.sendMedia.prepare", err.response.data),
|
|
547
551
|
);
|
|
548
552
|
}
|
|
@@ -559,7 +563,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
559
563
|
? preparedMedia.path
|
|
560
564
|
: resolveRelativePath(preparedMedia.path);
|
|
561
565
|
|
|
562
|
-
|
|
566
|
+
effectiveLog?.debug?.(
|
|
563
567
|
`[DingTalk] sendMedia resolved path: rawMediaPath=${rawMediaPath}, actualMediaPath=${actualMediaPath}`,
|
|
564
568
|
);
|
|
565
569
|
|
|
@@ -571,7 +575,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
571
575
|
let result;
|
|
572
576
|
try {
|
|
573
577
|
result = await sendProactiveMedia(config, to, actualMediaPath, mediaType, {
|
|
574
|
-
log,
|
|
578
|
+
log: effectiveLog,
|
|
575
579
|
accountId,
|
|
576
580
|
storePath,
|
|
577
581
|
conversationId: to,
|
|
@@ -579,7 +583,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
579
583
|
});
|
|
580
584
|
} catch (err: any) {
|
|
581
585
|
if (err?.response?.data !== undefined) {
|
|
582
|
-
|
|
586
|
+
effectiveLog?.error?.(
|
|
583
587
|
formatDingTalkErrorPayloadLog("outbound.sendMedia.send", err.response.data),
|
|
584
588
|
);
|
|
585
589
|
}
|
|
@@ -587,7 +591,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
587
591
|
cause: err,
|
|
588
592
|
});
|
|
589
593
|
}
|
|
590
|
-
|
|
594
|
+
effectiveLog?.debug?.(
|
|
591
595
|
`[DingTalk] sendMedia: ${mediaType} file=${actualMediaPath} result: ${JSON.stringify(result)}`,
|
|
592
596
|
);
|
|
593
597
|
|
|
@@ -609,7 +613,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
609
613
|
);
|
|
610
614
|
} catch (err: any) {
|
|
611
615
|
if (err?.response?.data !== undefined) {
|
|
612
|
-
|
|
616
|
+
effectiveLog?.error?.(formatDingTalkErrorPayloadLog("outbound.sendMedia", err.response.data));
|
|
613
617
|
}
|
|
614
618
|
throw new Error(
|
|
615
619
|
typeof err?.response?.data === "string"
|
|
@@ -639,29 +643,37 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
639
643
|
accountStorePath = undefined;
|
|
640
644
|
}
|
|
641
645
|
|
|
642
|
-
|
|
646
|
+
const pluginLog = resolvePluginDebugLog({
|
|
647
|
+
accountId: account.accountId,
|
|
648
|
+
storePath: accountStorePath,
|
|
649
|
+
debug: config.debug,
|
|
650
|
+
baseLog: ctx.log,
|
|
651
|
+
});
|
|
652
|
+
setCurrentLogger(pluginLog, account.accountId);
|
|
653
|
+
|
|
654
|
+
pluginLog?.info?.(`[${account.accountId}] Initializing DingTalk Stream client...`);
|
|
643
655
|
|
|
644
656
|
// Preload known peer IDs from sessions so outbound delivery (e.g. cron
|
|
645
657
|
// jobs that fire immediately after startup) can resolve the original
|
|
646
658
|
// case-sensitive conversationId before any inbound message has arrived.
|
|
647
659
|
preloadPeerIdsFromSessions();
|
|
648
|
-
|
|
660
|
+
pluginLog?.debug?.(`[${account.accountId}] Peer ID registry preloaded from sessions`);
|
|
649
661
|
|
|
650
|
-
cleanupOrphanedTempFiles(
|
|
662
|
+
cleanupOrphanedTempFiles(pluginLog);
|
|
651
663
|
try {
|
|
652
664
|
const recovered = await recoverPendingCardsForAccount(
|
|
653
665
|
config,
|
|
654
666
|
account.accountId,
|
|
655
667
|
accountStorePath,
|
|
656
|
-
|
|
668
|
+
pluginLog,
|
|
657
669
|
);
|
|
658
670
|
if (recovered > 0) {
|
|
659
|
-
|
|
671
|
+
pluginLog?.info?.(
|
|
660
672
|
`[${account.accountId}] Recovered and finalized ${recovered} unfinished card(s) from previous runtime`,
|
|
661
673
|
);
|
|
662
674
|
}
|
|
663
675
|
} catch (err: any) {
|
|
664
|
-
|
|
676
|
+
pluginLog?.warn?.(
|
|
665
677
|
`[${account.accountId}] Failed to recover unfinished cards: ${err.message}`,
|
|
666
678
|
);
|
|
667
679
|
}
|
|
@@ -683,7 +695,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
683
695
|
});
|
|
684
696
|
(c as any).sslopts = {
|
|
685
697
|
...(c as any).sslopts,
|
|
686
|
-
lookup: createResolve4FallbackLookup(
|
|
698
|
+
lookup: createResolve4FallbackLookup(pluginLog, account.accountId),
|
|
687
699
|
};
|
|
688
700
|
|
|
689
701
|
instrumentConnectionStages(c);
|
|
@@ -702,7 +714,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
702
714
|
c.socketCallBackResponse(messageId, { success: true });
|
|
703
715
|
stats.acked += 1;
|
|
704
716
|
} catch (ackError: any) {
|
|
705
|
-
|
|
717
|
+
pluginLog?.warn?.(
|
|
706
718
|
`[${account.accountId}] Failed to acknowledge callback ${messageId}: ${ackError.message}`,
|
|
707
719
|
);
|
|
708
720
|
}
|
|
@@ -723,38 +735,38 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
723
735
|
accountId: account.accountId,
|
|
724
736
|
data,
|
|
725
737
|
sessionWebhook: data.sessionWebhook,
|
|
726
|
-
log:
|
|
738
|
+
log: pluginLog,
|
|
727
739
|
dingtalkConfig: config,
|
|
728
740
|
});
|
|
729
741
|
stats.processed += 1;
|
|
730
742
|
if (stats.received % INBOUND_COUNTER_LOG_EVERY === 0) {
|
|
731
|
-
logInboundCounters(
|
|
743
|
+
logInboundCounters(pluginLog, account.accountId, "periodic");
|
|
732
744
|
}
|
|
733
745
|
return;
|
|
734
746
|
}
|
|
735
747
|
|
|
736
748
|
if (isMessageProcessed(dedupKey)) {
|
|
737
|
-
|
|
749
|
+
pluginLog?.debug?.(`[${account.accountId}] Skipping duplicate message: ${dedupKey}`);
|
|
738
750
|
stats.dedupSkipped += 1;
|
|
739
751
|
acknowledge();
|
|
740
|
-
logInboundCounters(
|
|
752
|
+
logInboundCounters(pluginLog, account.accountId, "dedup-skipped");
|
|
741
753
|
return;
|
|
742
754
|
}
|
|
743
755
|
|
|
744
756
|
const inflightSince = processingDedupKeys.get(dedupKey);
|
|
745
757
|
if (inflightSince !== undefined) {
|
|
746
758
|
if (Date.now() - inflightSince > INFLIGHT_TTL_MS) {
|
|
747
|
-
|
|
759
|
+
pluginLog?.warn?.(
|
|
748
760
|
`[${account.accountId}] Releasing stale in-flight lock for ${dedupKey} (held ${Date.now() - inflightSince}ms > TTL ${INFLIGHT_TTL_MS}ms)`,
|
|
749
761
|
);
|
|
750
762
|
processingDedupKeys.delete(dedupKey);
|
|
751
763
|
} else {
|
|
752
|
-
|
|
764
|
+
pluginLog?.debug?.(
|
|
753
765
|
`[${account.accountId}] Skipping in-flight duplicate message: ${dedupKey}`,
|
|
754
766
|
);
|
|
755
767
|
stats.inflightSkipped += 1;
|
|
756
768
|
acknowledge();
|
|
757
|
-
logInboundCounters(
|
|
769
|
+
logInboundCounters(pluginLog, account.accountId, "inflight-skipped");
|
|
758
770
|
return;
|
|
759
771
|
}
|
|
760
772
|
}
|
|
@@ -767,21 +779,21 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
767
779
|
accountId: account.accountId,
|
|
768
780
|
data,
|
|
769
781
|
sessionWebhook: data.sessionWebhook,
|
|
770
|
-
log:
|
|
782
|
+
log: pluginLog,
|
|
771
783
|
dingtalkConfig: config,
|
|
772
784
|
});
|
|
773
785
|
stats.processed += 1;
|
|
774
786
|
markMessageProcessed(dedupKey);
|
|
775
787
|
if (stats.received % INBOUND_COUNTER_LOG_EVERY === 0) {
|
|
776
|
-
logInboundCounters(
|
|
788
|
+
logInboundCounters(pluginLog, account.accountId, "periodic");
|
|
777
789
|
}
|
|
778
790
|
} finally {
|
|
779
791
|
processingDedupKeys.delete(dedupKey);
|
|
780
792
|
}
|
|
781
793
|
} catch (error: any) {
|
|
782
794
|
stats.failed += 1;
|
|
783
|
-
logInboundCounters(
|
|
784
|
-
|
|
795
|
+
logInboundCounters(pluginLog, account.accountId, "failed");
|
|
796
|
+
pluginLog?.error?.(`[${account.accountId}] Error processing message: ${error.message}`);
|
|
785
797
|
}
|
|
786
798
|
});
|
|
787
799
|
|
|
@@ -794,7 +806,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
794
806
|
try {
|
|
795
807
|
c.socketCallBackResponse(messageId, { success: true });
|
|
796
808
|
} catch (ackError: any) {
|
|
797
|
-
|
|
809
|
+
pluginLog?.warn?.(
|
|
798
810
|
`[${account.accountId}] Failed to acknowledge card callback ${messageId}: ${ackError.message}`,
|
|
799
811
|
);
|
|
800
812
|
}
|
|
@@ -803,7 +815,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
803
815
|
try {
|
|
804
816
|
const payload = JSON.parse(res.data);
|
|
805
817
|
const analysis = analyzeCardCallback(payload);
|
|
806
|
-
|
|
818
|
+
pluginLog?.info?.(
|
|
807
819
|
`[${account.accountId}] [DingTalk][CardCallback] action=${analysis.summary} raw=${JSON.stringify(payload)}`,
|
|
808
820
|
);
|
|
809
821
|
|
|
@@ -826,14 +838,14 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
826
838
|
analysis.feedbackAckText,
|
|
827
839
|
{
|
|
828
840
|
accountId: account.accountId,
|
|
829
|
-
log:
|
|
841
|
+
log: pluginLog,
|
|
830
842
|
},
|
|
831
843
|
);
|
|
832
|
-
|
|
844
|
+
pluginLog?.info?.(
|
|
833
845
|
`[${account.accountId}] [DingTalk][CardCallback] feedback ack sent to ${analysis.feedbackTarget}`,
|
|
834
846
|
);
|
|
835
847
|
} catch (sendErr: any) {
|
|
836
|
-
|
|
848
|
+
pluginLog?.warn?.(
|
|
837
849
|
`[${account.accountId}] [DingTalk][CardCallback] Failed to send feedback ack: ${sendErr?.message || String(sendErr)}`,
|
|
838
850
|
);
|
|
839
851
|
}
|
|
@@ -843,15 +855,15 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
843
855
|
cfg,
|
|
844
856
|
accountId: account.accountId,
|
|
845
857
|
config,
|
|
846
|
-
log:
|
|
858
|
+
log: pluginLog,
|
|
847
859
|
});
|
|
848
860
|
if (!actionResult.handled && analysis.actionId && analysis.actionId !== "feedback_up" && analysis.actionId !== "feedback_down") {
|
|
849
|
-
|
|
861
|
+
pluginLog?.debug?.(
|
|
850
862
|
`[${account.accountId}] [DingTalk][CardCallback] Unhandled actionId=${analysis.actionId}`,
|
|
851
863
|
);
|
|
852
864
|
}
|
|
853
865
|
} catch (error: any) {
|
|
854
|
-
|
|
866
|
+
pluginLog?.error?.(
|
|
855
867
|
`[${account.accountId}] [DingTalk][CardCallback] Failed to parse callback: ${error.message}`,
|
|
856
868
|
);
|
|
857
869
|
} finally {
|
|
@@ -877,15 +889,15 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
877
889
|
return;
|
|
878
890
|
}
|
|
879
891
|
stopped = true;
|
|
880
|
-
|
|
892
|
+
pluginLog?.info?.(`[${account.accountId}] Stopping DingTalk Stream client...`);
|
|
881
893
|
void finalizeActiveCardsForAccount(
|
|
882
894
|
config,
|
|
883
895
|
account.accountId,
|
|
884
896
|
"⚠️ 服务正在重启,当前回复已中断。请重新发送你的问题。",
|
|
885
897
|
accountStorePath,
|
|
886
|
-
|
|
898
|
+
pluginLog,
|
|
887
899
|
).catch((err: any) => {
|
|
888
|
-
|
|
900
|
+
pluginLog?.debug?.(
|
|
889
901
|
`[${account.accountId}] Failed to finalize active cards during stop: ${err.message}`,
|
|
890
902
|
);
|
|
891
903
|
});
|
|
@@ -895,7 +907,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
895
907
|
try {
|
|
896
908
|
client.disconnect();
|
|
897
909
|
} catch (err: any) {
|
|
898
|
-
|
|
910
|
+
pluginLog?.warn?.(`[${account.accountId}] Error during disconnect: ${err.message}`);
|
|
899
911
|
}
|
|
900
912
|
nativeStopResolve?.();
|
|
901
913
|
}
|
|
@@ -906,12 +918,16 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
906
918
|
lastStopAt: getCurrentTimestamp(),
|
|
907
919
|
});
|
|
908
920
|
|
|
909
|
-
|
|
921
|
+
pluginLog?.info?.(`[${account.accountId}] DingTalk Stream client stopped`);
|
|
922
|
+
closePluginDebugLog({
|
|
923
|
+
accountId: account.accountId,
|
|
924
|
+
storePath: accountStorePath,
|
|
925
|
+
});
|
|
910
926
|
};
|
|
911
927
|
|
|
912
928
|
if (abortSignal) {
|
|
913
929
|
if (abortSignal.aborted) {
|
|
914
|
-
|
|
930
|
+
pluginLog?.warn?.(
|
|
915
931
|
`[${account.accountId}] Abort signal already active, skipping connection`,
|
|
916
932
|
);
|
|
917
933
|
|
|
@@ -929,7 +945,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
929
945
|
if (stopped) {
|
|
930
946
|
return;
|
|
931
947
|
}
|
|
932
|
-
|
|
948
|
+
pluginLog?.info?.(
|
|
933
949
|
`[${account.accountId}] Abort signal received, stopping DingTalk Stream client...`,
|
|
934
950
|
);
|
|
935
951
|
stopClient();
|
|
@@ -946,11 +962,11 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
946
962
|
lastStartAt: getCurrentTimestamp(),
|
|
947
963
|
lastError: null,
|
|
948
964
|
});
|
|
949
|
-
|
|
965
|
+
pluginLog?.info?.(`[${account.accountId}] DingTalk Stream client connected successfully`);
|
|
950
966
|
await nativeStopPromise;
|
|
951
967
|
}
|
|
952
968
|
} catch (err: any) {
|
|
953
|
-
|
|
969
|
+
pluginLog?.error?.(
|
|
954
970
|
formatDingTalkConnectionErrorLog(
|
|
955
971
|
// Use connect.open as base scope; instrumentation can override to connect.websocket
|
|
956
972
|
"connect.open",
|
|
@@ -984,7 +1000,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
984
1000
|
if (stopped) {
|
|
985
1001
|
return;
|
|
986
1002
|
}
|
|
987
|
-
|
|
1003
|
+
pluginLog?.debug?.(
|
|
988
1004
|
`[${account.accountId}] Connection state changed to: ${state}${error ? ` (${error})` : ""}`,
|
|
989
1005
|
);
|
|
990
1006
|
if (state === ConnectionState.CONNECTED) {
|
|
@@ -1007,7 +1023,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
1007
1023
|
}
|
|
1008
1024
|
}
|
|
1009
1025
|
if (cleared > 0) {
|
|
1010
|
-
|
|
1026
|
+
pluginLog?.info?.(
|
|
1011
1027
|
`[${account.accountId}] Cleared ${cleared} stale in-flight lock(s) on disconnect`,
|
|
1012
1028
|
);
|
|
1013
1029
|
}
|
|
@@ -1020,7 +1036,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
1020
1036
|
},
|
|
1021
1037
|
};
|
|
1022
1038
|
|
|
1023
|
-
|
|
1039
|
+
pluginLog?.debug?.(
|
|
1024
1040
|
`[${account.accountId}] Connection config: maxAttempts=${connectionConfig.maxAttempts}, ` +
|
|
1025
1041
|
`initialDelay=${connectionConfig.initialDelay}ms, maxDelay=${connectionConfig.maxDelay}ms, ` +
|
|
1026
1042
|
`jitter=${connectionConfig.jitter}`,
|
|
@@ -1030,7 +1046,7 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
1030
1046
|
client,
|
|
1031
1047
|
account.accountId,
|
|
1032
1048
|
connectionConfig,
|
|
1033
|
-
|
|
1049
|
+
pluginLog,
|
|
1034
1050
|
createStreamClient,
|
|
1035
1051
|
);
|
|
1036
1052
|
|
|
@@ -1044,17 +1060,17 @@ export const dingtalkPlugin: DingTalkChannelPlugin = {
|
|
|
1044
1060
|
lastStartAt: getCurrentTimestamp(),
|
|
1045
1061
|
lastError: null,
|
|
1046
1062
|
});
|
|
1047
|
-
|
|
1063
|
+
pluginLog?.info?.(`[${account.accountId}] DingTalk Stream client connected successfully`);
|
|
1048
1064
|
|
|
1049
1065
|
await connectionManager.waitForStop();
|
|
1050
1066
|
} else {
|
|
1051
|
-
|
|
1067
|
+
pluginLog?.info?.(
|
|
1052
1068
|
`[${account.accountId}] DingTalk Stream client connect() completed but channel is ` +
|
|
1053
1069
|
`not running (stopped=${stopped}, connected=${connectionManager.isConnected()})`,
|
|
1054
1070
|
);
|
|
1055
1071
|
}
|
|
1056
1072
|
} catch (err: any) {
|
|
1057
|
-
|
|
1073
|
+
pluginLog?.error?.(
|
|
1058
1074
|
formatDingTalkConnectionErrorLog(
|
|
1059
1075
|
// Use connect.open as base scope; instrumentation can override to connect.websocket
|
|
1060
1076
|
"connect.open",
|
|
@@ -1,26 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { resolveNativeCommandSessionTargets } from "openclaw/plugin-sdk/command-auth";
|
|
2
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
2
3
|
import { getDingTalkRuntime } from "../runtime";
|
|
3
4
|
import type { Logger } from "../types";
|
|
4
5
|
|
|
5
|
-
/**
|
|
6
|
-
* Local implementation of the same logic as
|
|
7
|
-
* `resolveNativeCommandSessionTargets` from `openclaw/plugin-sdk/command-auth`.
|
|
8
|
-
*
|
|
9
|
-
* Inlined because the CI openclaw package does not yet export that sub-path.
|
|
10
|
-
* Replace with a direct import once the upstream package is updated.
|
|
11
|
-
*/
|
|
12
|
-
function resolveNativeCommandSessionTargets(params: {
|
|
13
|
-
agentId: string;
|
|
14
|
-
sessionPrefix: string;
|
|
15
|
-
userId: string;
|
|
16
|
-
targetSessionKey: string;
|
|
17
|
-
}): { sessionKey: string; commandTargetSessionKey: string } {
|
|
18
|
-
return {
|
|
19
|
-
sessionKey: `agent:${params.agentId}:${params.sessionPrefix}:${params.userId}`,
|
|
20
|
-
commandTargetSessionKey: params.targetSessionKey,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
6
|
/**
|
|
25
7
|
* Dispatch a native targeted `/stop` command through the OpenClaw SDK,
|
|
26
8
|
* replacing the previous self-built Gateway WebSocket `chat.abort` approach.
|
|
@@ -35,8 +17,8 @@ function resolveNativeCommandSessionTargets(params: {
|
|
|
35
17
|
* and executes `abortEmbeddedPiRun` + `clearSessionQueues`.
|
|
36
18
|
*
|
|
37
19
|
* Accesses SDK functions via `getDingTalkRuntime().channel.reply` — the same
|
|
38
|
-
* pattern used by `inbound-handler.ts` —
|
|
39
|
-
*
|
|
20
|
+
* pattern used by `inbound-handler.ts` — while reusing the upstream native
|
|
21
|
+
* command session-target helper exported by the plugin SDK.
|
|
40
22
|
*/
|
|
41
23
|
export async function dispatchDingTalkCardStopCommand(params: {
|
|
42
24
|
cfg: OpenClawConfig;
|