@clawling/clawchat-plugin-openclaw 2026.5.12-39 → 2026.5.13-dev.1

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.
@@ -3,7 +3,7 @@ import { resolveOutboundMediaUrls } from "openclaw/plugin-sdk/reply-payload";
3
3
  import { createOpenclawClawlingApiClient } from "./api-client.js";
4
4
  import { effectiveOutputVisibility, } from "./config.js";
5
5
  import { uploadOutboundMedia } from "./media-runtime.js";
6
- import { sendOpenclawClawlingText, } from "./outbound.js";
6
+ import { mintMessageId, sendOpenclawClawlingText, } from "./outbound.js";
7
7
  import { isClawChatNoopResponseText } from "./profile-prompt.js";
8
8
  import { consumeTerminalClawChatSend } from "./terminal-send.js";
9
9
  import { openclawLlmContextDebug } from "./llm-context-debug.js";
@@ -259,8 +259,7 @@ 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";
263
- const splitNormalBlockOutput = outputVisibility === "normal";
262
+ const splitFullOutput = outputVisibility === "full" && !isGroupTarget;
264
263
  const ownerDirectTarget = () => {
265
264
  const ownerUserId = account.ownerUserId?.trim();
266
265
  return ownerUserId ? { chatId: ownerUserId, chatType: "direct" } : null;
@@ -416,7 +415,10 @@ export function createOpenclawClawlingReplyDispatcher(options) {
416
415
  }
417
416
  return merged;
418
417
  };
419
- const mintStaticMessageId = () => `${account.userId}-msg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
418
+ // §7.6 (binding): client-supplied message_id MUST be `msg-` + a 26-char
419
+ // Crockford base32 ULID. Use the shared conformant minter — do not invent a
420
+ // different scheme (planned msghub Phase-4 validation will reject it).
421
+ const mintStaticMessageId = () => mintMessageId();
420
422
  const emitTyping = (isTyping) => {
421
423
  if (!isTyping && !typingActive)
422
424
  return;
@@ -524,12 +526,12 @@ export function createOpenclawClawlingReplyDispatcher(options) {
524
526
  return result;
525
527
  };
526
528
  const emitFullSegment = async (text, urls = []) => {
527
- if (outputVisibility !== "full" && !splitNormalBlockOutput) {
529
+ if (outputVisibility !== "full") {
528
530
  appendBufferedText(text);
529
531
  appendBufferedUrls(urls);
530
532
  return;
531
533
  }
532
- if (!splitFullOutput && !splitNormalBlockOutput) {
534
+ if (!splitFullOutput) {
533
535
  appendBufferedText(text);
534
536
  appendBufferedUrls(urls);
535
537
  return;
@@ -597,9 +599,6 @@ export function createOpenclawClawlingReplyDispatcher(options) {
597
599
  if (outputVisibility === "full") {
598
600
  await emitFullSegment(text, urls);
599
601
  }
600
- else if (splitNormalBlockOutput) {
601
- await emitFullSegment(text, urls);
602
- }
603
602
  else if (outputVisibility === "minimal" || outputVisibility === "normal") {
604
603
  appendBufferedText(text);
605
604
  appendBufferedUrls(urls);
@@ -631,12 +630,6 @@ export function createOpenclawClawlingReplyDispatcher(options) {
631
630
  }
632
631
  const finalText = richFragment && account.richInteractions ? mergeFinalText("") : mergeFinalText(text);
633
632
  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
- }
640
633
  const mediaFragments = await uploadMediaUrls(finalUrls);
641
634
  const result = await sendStatic(finalText, mediaFragments, richFragment && account.richInteractions ? [richFragment] : [], { recordMessage: true });
642
635
  if (result?.messageId)
@@ -648,8 +641,12 @@ export function createOpenclawClawlingReplyDispatcher(options) {
648
641
  onError: (error, info) => {
649
642
  const errorText = normalizeReplyErrorText(error);
650
643
  log?.error?.(`[${account.accountId}] clawchat-plugin-openclaw ${info.kind} reply failed: ${errorText}`);
651
- if (outputVisibility === "full")
644
+ if (!isGroupTarget && outputVisibility === "full")
652
645
  void emitFullRuntimeText("error", errorText);
646
+ if (isGroupTarget) {
647
+ log?.error?.(`[${account.accountId}] clawchat-plugin-openclaw group runtime failure suppressed from ClawChat clients group=${target.chatId}`);
648
+ return;
649
+ }
653
650
  },
654
651
  onIdle: async () => {
655
652
  emitTyping(false);
@@ -676,10 +673,10 @@ export function createOpenclawClawlingReplyDispatcher(options) {
676
673
  replyOptions: {
677
674
  ...base.replyOptions,
678
675
  sourceReplyDeliveryMode: "automatic",
679
- disableBlockStreaming: !splitNormalBlockOutput,
676
+ disableBlockStreaming: true,
680
677
  suppressDefaultToolProgressMessages: true,
681
- allowProgressCallbacksWhenSourceDeliverySuppressed: splitFullOutput ? true : undefined,
682
- onReasoningStream: splitFullOutput
678
+ allowProgressCallbacksWhenSourceDeliverySuppressed: outputVisibility === "full" ? true : undefined,
679
+ onReasoningStream: outputVisibility === "full"
683
680
  ? async (payload) => {
684
681
  if (consumeTerminalSend("reasoning"))
685
682
  return;
@@ -690,14 +687,14 @@ export function createOpenclawClawlingReplyDispatcher(options) {
690
687
  reasoningText = reasoningText ? `${reasoningText}\n${trimmed}` : trimmed;
691
688
  }
692
689
  : undefined,
693
- onToolStart: splitFullOutput
690
+ onToolStart: outputVisibility === "full"
694
691
  ? async (payload) => {
695
692
  if (consumeTerminalSend("tool-start"))
696
693
  return;
697
694
  await emitFullSegment(formatToolStartSummary(payload));
698
695
  }
699
696
  : undefined,
700
- onToolResult: splitFullOutput
697
+ onToolResult: outputVisibility === "full"
701
698
  ? async (payload) => {
702
699
  if (consumeTerminalSend("tool-result"))
703
700
  return;
@@ -707,7 +704,7 @@ export function createOpenclawClawlingReplyDispatcher(options) {
707
704
  await emitFullRuntimeText("tool result", text, resolveOutboundMediaUrls(payload).filter(Boolean));
708
705
  }
709
706
  : undefined,
710
- onItemEvent: splitFullOutput
707
+ onItemEvent: outputVisibility === "full"
711
708
  ? async (payload) => {
712
709
  if (consumeTerminalSend("item-event"))
713
710
  return;
@@ -716,35 +713,35 @@ export function createOpenclawClawlingReplyDispatcher(options) {
716
713
  await emitFullRuntimeText("progress", summarizeProgressPayload(payload));
717
714
  }
718
715
  : undefined,
719
- onPlanUpdate: splitFullOutput
716
+ onPlanUpdate: outputVisibility === "full"
720
717
  ? async (payload) => {
721
718
  if (consumeTerminalSend("plan-update"))
722
719
  return;
723
720
  await emitFullRuntimeText("plan", summarizeProgressPayload(payload));
724
721
  }
725
722
  : undefined,
726
- onCommandOutput: splitFullOutput
723
+ onCommandOutput: outputVisibility === "full"
727
724
  ? async (payload) => {
728
725
  if (consumeTerminalSend("command-output"))
729
726
  return;
730
727
  await emitFullSegment(formatCommandOutputSummary(payload));
731
728
  }
732
729
  : undefined,
733
- onPatchSummary: splitFullOutput
730
+ onPatchSummary: outputVisibility === "full"
734
731
  ? async (payload) => {
735
732
  if (consumeTerminalSend("patch-summary"))
736
733
  return;
737
734
  await emitFullSegment(formatPatchSummary(payload));
738
735
  }
739
736
  : undefined,
740
- onCompactionStart: splitFullOutput
737
+ onCompactionStart: outputVisibility === "full"
741
738
  ? async () => {
742
739
  if (consumeTerminalSend("compaction-start"))
743
740
  return;
744
741
  await emitFullSegment("[compaction] started");
745
742
  }
746
743
  : undefined,
747
- onCompactionEnd: splitFullOutput
744
+ onCompactionEnd: outputVisibility === "full"
748
745
  ? async () => {
749
746
  if (consumeTerminalSend("compaction-end"))
750
747
  return;