@clawling/clawchat-plugin-openclaw 2026.5.12-38 → 2026.5.12-39
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/src/reply-dispatcher.js +25 -19
- package/package.json +1 -1
- package/skills/clawchat/SKILL.md +13 -0
- package/src/reply-dispatcher.ts +26 -21
|
@@ -259,7 +259,8 @@ export function createOpenclawClawlingReplyDispatcher(options) {
|
|
|
259
259
|
const { cfg, runtime, account, client, target, replyCtx, inboundMessageId, store, log, } = options;
|
|
260
260
|
const isGroupTarget = target.chatType === "group";
|
|
261
261
|
const outputVisibility = effectiveOutputVisibility(account, target.chatId, target.chatType);
|
|
262
|
-
const splitFullOutput = outputVisibility === "full"
|
|
262
|
+
const splitFullOutput = outputVisibility === "full";
|
|
263
|
+
const splitNormalBlockOutput = outputVisibility === "normal";
|
|
263
264
|
const ownerDirectTarget = () => {
|
|
264
265
|
const ownerUserId = account.ownerUserId?.trim();
|
|
265
266
|
return ownerUserId ? { chatId: ownerUserId, chatType: "direct" } : null;
|
|
@@ -523,12 +524,12 @@ export function createOpenclawClawlingReplyDispatcher(options) {
|
|
|
523
524
|
return result;
|
|
524
525
|
};
|
|
525
526
|
const emitFullSegment = async (text, urls = []) => {
|
|
526
|
-
if (outputVisibility !== "full") {
|
|
527
|
+
if (outputVisibility !== "full" && !splitNormalBlockOutput) {
|
|
527
528
|
appendBufferedText(text);
|
|
528
529
|
appendBufferedUrls(urls);
|
|
529
530
|
return;
|
|
530
531
|
}
|
|
531
|
-
if (!splitFullOutput) {
|
|
532
|
+
if (!splitFullOutput && !splitNormalBlockOutput) {
|
|
532
533
|
appendBufferedText(text);
|
|
533
534
|
appendBufferedUrls(urls);
|
|
534
535
|
return;
|
|
@@ -596,6 +597,9 @@ export function createOpenclawClawlingReplyDispatcher(options) {
|
|
|
596
597
|
if (outputVisibility === "full") {
|
|
597
598
|
await emitFullSegment(text, urls);
|
|
598
599
|
}
|
|
600
|
+
else if (splitNormalBlockOutput) {
|
|
601
|
+
await emitFullSegment(text, urls);
|
|
602
|
+
}
|
|
599
603
|
else if (outputVisibility === "minimal" || outputVisibility === "normal") {
|
|
600
604
|
appendBufferedText(text);
|
|
601
605
|
appendBufferedUrls(urls);
|
|
@@ -627,6 +631,12 @@ export function createOpenclawClawlingReplyDispatcher(options) {
|
|
|
627
631
|
}
|
|
628
632
|
const finalText = richFragment && account.richInteractions ? mergeFinalText("") : mergeFinalText(text);
|
|
629
633
|
const finalUrls = mergeFinalUrls(urls);
|
|
634
|
+
if (isClawChatNoopResponseText(finalText) &&
|
|
635
|
+
!richFragment &&
|
|
636
|
+
finalUrls.length === 0) {
|
|
637
|
+
log?.info?.(`[${account.accountId}] clawchat-plugin-openclaw final suppressed: no-reply token`);
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
630
640
|
const mediaFragments = await uploadMediaUrls(finalUrls);
|
|
631
641
|
const result = await sendStatic(finalText, mediaFragments, richFragment && account.richInteractions ? [richFragment] : [], { recordMessage: true });
|
|
632
642
|
if (result?.messageId)
|
|
@@ -638,12 +648,8 @@ export function createOpenclawClawlingReplyDispatcher(options) {
|
|
|
638
648
|
onError: (error, info) => {
|
|
639
649
|
const errorText = normalizeReplyErrorText(error);
|
|
640
650
|
log?.error?.(`[${account.accountId}] clawchat-plugin-openclaw ${info.kind} reply failed: ${errorText}`);
|
|
641
|
-
if (
|
|
651
|
+
if (outputVisibility === "full")
|
|
642
652
|
void emitFullRuntimeText("error", errorText);
|
|
643
|
-
if (isGroupTarget) {
|
|
644
|
-
log?.error?.(`[${account.accountId}] clawchat-plugin-openclaw group runtime failure suppressed from ClawChat clients group=${target.chatId}`);
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
653
|
},
|
|
648
654
|
onIdle: async () => {
|
|
649
655
|
emitTyping(false);
|
|
@@ -670,10 +676,10 @@ export function createOpenclawClawlingReplyDispatcher(options) {
|
|
|
670
676
|
replyOptions: {
|
|
671
677
|
...base.replyOptions,
|
|
672
678
|
sourceReplyDeliveryMode: "automatic",
|
|
673
|
-
disableBlockStreaming:
|
|
679
|
+
disableBlockStreaming: !splitNormalBlockOutput,
|
|
674
680
|
suppressDefaultToolProgressMessages: true,
|
|
675
|
-
allowProgressCallbacksWhenSourceDeliverySuppressed:
|
|
676
|
-
onReasoningStream:
|
|
681
|
+
allowProgressCallbacksWhenSourceDeliverySuppressed: splitFullOutput ? true : undefined,
|
|
682
|
+
onReasoningStream: splitFullOutput
|
|
677
683
|
? async (payload) => {
|
|
678
684
|
if (consumeTerminalSend("reasoning"))
|
|
679
685
|
return;
|
|
@@ -684,14 +690,14 @@ export function createOpenclawClawlingReplyDispatcher(options) {
|
|
|
684
690
|
reasoningText = reasoningText ? `${reasoningText}\n${trimmed}` : trimmed;
|
|
685
691
|
}
|
|
686
692
|
: undefined,
|
|
687
|
-
onToolStart:
|
|
693
|
+
onToolStart: splitFullOutput
|
|
688
694
|
? async (payload) => {
|
|
689
695
|
if (consumeTerminalSend("tool-start"))
|
|
690
696
|
return;
|
|
691
697
|
await emitFullSegment(formatToolStartSummary(payload));
|
|
692
698
|
}
|
|
693
699
|
: undefined,
|
|
694
|
-
onToolResult:
|
|
700
|
+
onToolResult: splitFullOutput
|
|
695
701
|
? async (payload) => {
|
|
696
702
|
if (consumeTerminalSend("tool-result"))
|
|
697
703
|
return;
|
|
@@ -701,7 +707,7 @@ export function createOpenclawClawlingReplyDispatcher(options) {
|
|
|
701
707
|
await emitFullRuntimeText("tool result", text, resolveOutboundMediaUrls(payload).filter(Boolean));
|
|
702
708
|
}
|
|
703
709
|
: undefined,
|
|
704
|
-
onItemEvent:
|
|
710
|
+
onItemEvent: splitFullOutput
|
|
705
711
|
? async (payload) => {
|
|
706
712
|
if (consumeTerminalSend("item-event"))
|
|
707
713
|
return;
|
|
@@ -710,35 +716,35 @@ export function createOpenclawClawlingReplyDispatcher(options) {
|
|
|
710
716
|
await emitFullRuntimeText("progress", summarizeProgressPayload(payload));
|
|
711
717
|
}
|
|
712
718
|
: undefined,
|
|
713
|
-
onPlanUpdate:
|
|
719
|
+
onPlanUpdate: splitFullOutput
|
|
714
720
|
? async (payload) => {
|
|
715
721
|
if (consumeTerminalSend("plan-update"))
|
|
716
722
|
return;
|
|
717
723
|
await emitFullRuntimeText("plan", summarizeProgressPayload(payload));
|
|
718
724
|
}
|
|
719
725
|
: undefined,
|
|
720
|
-
onCommandOutput:
|
|
726
|
+
onCommandOutput: splitFullOutput
|
|
721
727
|
? async (payload) => {
|
|
722
728
|
if (consumeTerminalSend("command-output"))
|
|
723
729
|
return;
|
|
724
730
|
await emitFullSegment(formatCommandOutputSummary(payload));
|
|
725
731
|
}
|
|
726
732
|
: undefined,
|
|
727
|
-
onPatchSummary:
|
|
733
|
+
onPatchSummary: splitFullOutput
|
|
728
734
|
? async (payload) => {
|
|
729
735
|
if (consumeTerminalSend("patch-summary"))
|
|
730
736
|
return;
|
|
731
737
|
await emitFullSegment(formatPatchSummary(payload));
|
|
732
738
|
}
|
|
733
739
|
: undefined,
|
|
734
|
-
onCompactionStart:
|
|
740
|
+
onCompactionStart: splitFullOutput
|
|
735
741
|
? async () => {
|
|
736
742
|
if (consumeTerminalSend("compaction-start"))
|
|
737
743
|
return;
|
|
738
744
|
await emitFullSegment("[compaction] started");
|
|
739
745
|
}
|
|
740
746
|
: undefined,
|
|
741
|
-
onCompactionEnd:
|
|
747
|
+
onCompactionEnd: splitFullOutput
|
|
742
748
|
? async () => {
|
|
743
749
|
if (consumeTerminalSend("compaction-end"))
|
|
744
750
|
return;
|
package/package.json
CHANGED
package/skills/clawchat/SKILL.md
CHANGED
|
@@ -13,6 +13,7 @@ This skill guides agent behavior for ClawChat-aware tasks. Use the registered Cl
|
|
|
13
13
|
|
|
14
14
|
- Use registered ClawChat plugin tools for account/profile, friends, users, moments, comments, reactions, avatar, media, and read-only conversation lookup.
|
|
15
15
|
- If a requested ClawChat tool is unavailable or returns a config error, report that result and stop instead of bypassing the plugin.
|
|
16
|
+
- Use the `/clawchat-output` slash command when the user asks to change how much ClawChat runtime output is shown in the current conversation.
|
|
16
17
|
|
|
17
18
|
## OpenClaw CLI
|
|
18
19
|
|
|
@@ -30,6 +31,18 @@ Use `update --force` only when local ClawChat plugin or skill files look corrupt
|
|
|
30
31
|
|
|
31
32
|
If `channels add` reports `Unknown channel: clawchat-plugin-openclaw`, use the runtime slash command `/clawchat-activate CODE` after the operator ensures the plugin is loaded.
|
|
32
33
|
|
|
34
|
+
## Output Visibility
|
|
35
|
+
|
|
36
|
+
When the user asks to change ClawChat output verbosity, use the runtime slash command for the current conversation. Treat natural-language wording as aliases for the three supported modes:
|
|
37
|
+
|
|
38
|
+
| User wording | Command |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| quiet mode, silent mode, minimal output, final-only output, `minimal` | `/clawchat-output minimal` |
|
|
41
|
+
| conversation mode, normal mode, regular mode, default output, `normal` | `/clawchat-output normal` |
|
|
42
|
+
| dev mode, developer mode, verbose mode, full output, `full` | `/clawchat-output full` |
|
|
43
|
+
|
|
44
|
+
Do not edit config files directly for this request. If the slash command returns an error, report that error instead of claiming the mode changed.
|
|
45
|
+
|
|
33
46
|
## Plugin Tool Routing
|
|
34
47
|
|
|
35
48
|
Tool descriptions are authoritative. These routing hints resolve common ambiguity:
|
package/src/reply-dispatcher.ts
CHANGED
|
@@ -388,7 +388,8 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
|
|
|
388
388
|
} = options;
|
|
389
389
|
const isGroupTarget = target.chatType === "group";
|
|
390
390
|
const outputVisibility = effectiveOutputVisibility(account, target.chatId, target.chatType);
|
|
391
|
-
const splitFullOutput = outputVisibility === "full"
|
|
391
|
+
const splitFullOutput = outputVisibility === "full";
|
|
392
|
+
const splitNormalBlockOutput = outputVisibility === "normal";
|
|
392
393
|
const ownerDirectTarget = () => {
|
|
393
394
|
const ownerUserId = account.ownerUserId?.trim();
|
|
394
395
|
return ownerUserId ? { chatId: ownerUserId, chatType: "direct" as const } : null;
|
|
@@ -670,12 +671,12 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
|
|
|
670
671
|
};
|
|
671
672
|
|
|
672
673
|
const emitFullSegment = async (text: string, urls: string[] = []): Promise<void> => {
|
|
673
|
-
if (outputVisibility !== "full") {
|
|
674
|
+
if (outputVisibility !== "full" && !splitNormalBlockOutput) {
|
|
674
675
|
appendBufferedText(text);
|
|
675
676
|
appendBufferedUrls(urls);
|
|
676
677
|
return;
|
|
677
678
|
}
|
|
678
|
-
if (!splitFullOutput) {
|
|
679
|
+
if (!splitFullOutput && !splitNormalBlockOutput) {
|
|
679
680
|
appendBufferedText(text);
|
|
680
681
|
appendBufferedUrls(urls);
|
|
681
682
|
return;
|
|
@@ -750,6 +751,8 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
|
|
|
750
751
|
if (info?.kind === "block") {
|
|
751
752
|
if (outputVisibility === "full") {
|
|
752
753
|
await emitFullSegment(text, urls);
|
|
754
|
+
} else if (splitNormalBlockOutput) {
|
|
755
|
+
await emitFullSegment(text, urls);
|
|
753
756
|
} else if (outputVisibility === "minimal" || outputVisibility === "normal") {
|
|
754
757
|
appendBufferedText(text);
|
|
755
758
|
appendBufferedUrls(urls);
|
|
@@ -782,6 +785,14 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
|
|
|
782
785
|
}
|
|
783
786
|
const finalText = richFragment && account.richInteractions ? mergeFinalText("") : mergeFinalText(text);
|
|
784
787
|
const finalUrls = mergeFinalUrls(urls);
|
|
788
|
+
if (
|
|
789
|
+
isClawChatNoopResponseText(finalText) &&
|
|
790
|
+
!richFragment &&
|
|
791
|
+
finalUrls.length === 0
|
|
792
|
+
) {
|
|
793
|
+
log?.info?.(`[${account.accountId}] clawchat-plugin-openclaw final suppressed: no-reply token`);
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
785
796
|
const mediaFragments = await uploadMediaUrls(finalUrls);
|
|
786
797
|
const result = await sendStatic(
|
|
787
798
|
finalText,
|
|
@@ -800,13 +811,7 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
|
|
|
800
811
|
log?.error?.(
|
|
801
812
|
`[${account.accountId}] clawchat-plugin-openclaw ${info.kind} reply failed: ${errorText}`,
|
|
802
813
|
);
|
|
803
|
-
if (
|
|
804
|
-
if (isGroupTarget) {
|
|
805
|
-
log?.error?.(
|
|
806
|
-
`[${account.accountId}] clawchat-plugin-openclaw group runtime failure suppressed from ClawChat clients group=${target.chatId}`,
|
|
807
|
-
);
|
|
808
|
-
return;
|
|
809
|
-
}
|
|
814
|
+
if (outputVisibility === "full") void emitFullRuntimeText("error", errorText);
|
|
810
815
|
},
|
|
811
816
|
onIdle: async () => {
|
|
812
817
|
emitTyping(false);
|
|
@@ -830,10 +835,10 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
|
|
|
830
835
|
replyOptions: {
|
|
831
836
|
...base.replyOptions,
|
|
832
837
|
sourceReplyDeliveryMode: "automatic",
|
|
833
|
-
disableBlockStreaming:
|
|
838
|
+
disableBlockStreaming: !splitNormalBlockOutput,
|
|
834
839
|
suppressDefaultToolProgressMessages: true,
|
|
835
|
-
allowProgressCallbacksWhenSourceDeliverySuppressed:
|
|
836
|
-
onReasoningStream:
|
|
840
|
+
allowProgressCallbacksWhenSourceDeliverySuppressed: splitFullOutput ? true : undefined,
|
|
841
|
+
onReasoningStream: splitFullOutput
|
|
837
842
|
? async (payload: ReplyPayload) => {
|
|
838
843
|
if (consumeTerminalSend("reasoning")) return;
|
|
839
844
|
const text = resolvePayloadText(payload);
|
|
@@ -842,13 +847,13 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
|
|
|
842
847
|
if (trimmed) reasoningText = reasoningText ? `${reasoningText}\n${trimmed}` : trimmed;
|
|
843
848
|
}
|
|
844
849
|
: undefined,
|
|
845
|
-
onToolStart:
|
|
850
|
+
onToolStart: splitFullOutput
|
|
846
851
|
? async (payload) => {
|
|
847
852
|
if (consumeTerminalSend("tool-start")) return;
|
|
848
853
|
await emitFullSegment(formatToolStartSummary(payload));
|
|
849
854
|
}
|
|
850
855
|
: undefined,
|
|
851
|
-
onToolResult:
|
|
856
|
+
onToolResult: splitFullOutput
|
|
852
857
|
? async (payload: ReplyPayload) => {
|
|
853
858
|
if (consumeTerminalSend("tool-result")) return;
|
|
854
859
|
const text = resolvePayloadText(payload);
|
|
@@ -856,38 +861,38 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
|
|
|
856
861
|
await emitFullRuntimeText("tool result", text, resolveOutboundMediaUrls(payload).filter(Boolean));
|
|
857
862
|
}
|
|
858
863
|
: undefined,
|
|
859
|
-
onItemEvent:
|
|
864
|
+
onItemEvent: splitFullOutput
|
|
860
865
|
? async (payload: Record<string, unknown>) => {
|
|
861
866
|
if (consumeTerminalSend("item-event")) return;
|
|
862
867
|
if (isToolProgressItem(payload)) return;
|
|
863
868
|
await emitFullRuntimeText("progress", summarizeProgressPayload(payload));
|
|
864
869
|
}
|
|
865
870
|
: undefined,
|
|
866
|
-
onPlanUpdate:
|
|
871
|
+
onPlanUpdate: splitFullOutput
|
|
867
872
|
? async (payload: Record<string, unknown>) => {
|
|
868
873
|
if (consumeTerminalSend("plan-update")) return;
|
|
869
874
|
await emitFullRuntimeText("plan", summarizeProgressPayload(payload));
|
|
870
875
|
}
|
|
871
876
|
: undefined,
|
|
872
|
-
onCommandOutput:
|
|
877
|
+
onCommandOutput: splitFullOutput
|
|
873
878
|
? async (payload: Record<string, unknown>) => {
|
|
874
879
|
if (consumeTerminalSend("command-output")) return;
|
|
875
880
|
await emitFullSegment(formatCommandOutputSummary(payload));
|
|
876
881
|
}
|
|
877
882
|
: undefined,
|
|
878
|
-
onPatchSummary:
|
|
883
|
+
onPatchSummary: splitFullOutput
|
|
879
884
|
? async (payload: Record<string, unknown>) => {
|
|
880
885
|
if (consumeTerminalSend("patch-summary")) return;
|
|
881
886
|
await emitFullSegment(formatPatchSummary(payload));
|
|
882
887
|
}
|
|
883
888
|
: undefined,
|
|
884
|
-
onCompactionStart:
|
|
889
|
+
onCompactionStart: splitFullOutput
|
|
885
890
|
? async () => {
|
|
886
891
|
if (consumeTerminalSend("compaction-start")) return;
|
|
887
892
|
await emitFullSegment("[compaction] started");
|
|
888
893
|
}
|
|
889
894
|
: undefined,
|
|
890
|
-
onCompactionEnd:
|
|
895
|
+
onCompactionEnd: splitFullOutput
|
|
891
896
|
? async () => {
|
|
892
897
|
if (consumeTerminalSend("compaction-end")) return;
|
|
893
898
|
await emitFullSegment("[compaction] finished");
|