@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.
@@ -19,6 +19,7 @@ import {
19
19
  } from "./config.ts";
20
20
  import { uploadOutboundMedia, type ClawlingMediaFragment } from "./media-runtime.ts";
21
21
  import {
22
+ mintMessageId,
22
23
  sendOpenclawClawlingText,
23
24
  type OutboundReplyCtx,
24
25
  type SendResult,
@@ -388,8 +389,7 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
388
389
  } = options;
389
390
  const isGroupTarget = target.chatType === "group";
390
391
  const outputVisibility = effectiveOutputVisibility(account, target.chatId, target.chatType);
391
- const splitFullOutput = outputVisibility === "full";
392
- const splitNormalBlockOutput = outputVisibility === "normal";
392
+ const splitFullOutput = outputVisibility === "full" && !isGroupTarget;
393
393
  const ownerDirectTarget = () => {
394
394
  const ownerUserId = account.ownerUserId?.trim();
395
395
  return ownerUserId ? { chatId: ownerUserId, chatType: "direct" as const } : null;
@@ -543,8 +543,10 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
543
543
  return merged;
544
544
  };
545
545
 
546
- const mintStaticMessageId = () =>
547
- `${account.userId}-msg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
546
+ // §7.6 (binding): client-supplied message_id MUST be `msg-` + a 26-char
547
+ // Crockford base32 ULID. Use the shared conformant minter — do not invent a
548
+ // different scheme (planned msghub Phase-4 validation will reject it).
549
+ const mintStaticMessageId = () => mintMessageId();
548
550
 
549
551
  const emitTyping = (isTyping: boolean) => {
550
552
  if (!isTyping && !typingActive) return;
@@ -671,12 +673,12 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
671
673
  };
672
674
 
673
675
  const emitFullSegment = async (text: string, urls: string[] = []): Promise<void> => {
674
- if (outputVisibility !== "full" && !splitNormalBlockOutput) {
676
+ if (outputVisibility !== "full") {
675
677
  appendBufferedText(text);
676
678
  appendBufferedUrls(urls);
677
679
  return;
678
680
  }
679
- if (!splitFullOutput && !splitNormalBlockOutput) {
681
+ if (!splitFullOutput) {
680
682
  appendBufferedText(text);
681
683
  appendBufferedUrls(urls);
682
684
  return;
@@ -751,8 +753,6 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
751
753
  if (info?.kind === "block") {
752
754
  if (outputVisibility === "full") {
753
755
  await emitFullSegment(text, urls);
754
- } else if (splitNormalBlockOutput) {
755
- await emitFullSegment(text, urls);
756
756
  } else if (outputVisibility === "minimal" || outputVisibility === "normal") {
757
757
  appendBufferedText(text);
758
758
  appendBufferedUrls(urls);
@@ -785,14 +785,6 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
785
785
  }
786
786
  const finalText = richFragment && account.richInteractions ? mergeFinalText("") : mergeFinalText(text);
787
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
- }
796
788
  const mediaFragments = await uploadMediaUrls(finalUrls);
797
789
  const result = await sendStatic(
798
790
  finalText,
@@ -811,7 +803,13 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
811
803
  log?.error?.(
812
804
  `[${account.accountId}] clawchat-plugin-openclaw ${info.kind} reply failed: ${errorText}`,
813
805
  );
814
- if (outputVisibility === "full") void emitFullRuntimeText("error", errorText);
806
+ if (!isGroupTarget && outputVisibility === "full") void emitFullRuntimeText("error", errorText);
807
+ if (isGroupTarget) {
808
+ log?.error?.(
809
+ `[${account.accountId}] clawchat-plugin-openclaw group runtime failure suppressed from ClawChat clients group=${target.chatId}`,
810
+ );
811
+ return;
812
+ }
815
813
  },
816
814
  onIdle: async () => {
817
815
  emitTyping(false);
@@ -835,10 +833,10 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
835
833
  replyOptions: {
836
834
  ...base.replyOptions,
837
835
  sourceReplyDeliveryMode: "automatic",
838
- disableBlockStreaming: !splitNormalBlockOutput,
836
+ disableBlockStreaming: true,
839
837
  suppressDefaultToolProgressMessages: true,
840
- allowProgressCallbacksWhenSourceDeliverySuppressed: splitFullOutput ? true : undefined,
841
- onReasoningStream: splitFullOutput
838
+ allowProgressCallbacksWhenSourceDeliverySuppressed: outputVisibility === "full" ? true : undefined,
839
+ onReasoningStream: outputVisibility === "full"
842
840
  ? async (payload: ReplyPayload) => {
843
841
  if (consumeTerminalSend("reasoning")) return;
844
842
  const text = resolvePayloadText(payload);
@@ -847,13 +845,13 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
847
845
  if (trimmed) reasoningText = reasoningText ? `${reasoningText}\n${trimmed}` : trimmed;
848
846
  }
849
847
  : undefined,
850
- onToolStart: splitFullOutput
848
+ onToolStart: outputVisibility === "full"
851
849
  ? async (payload) => {
852
850
  if (consumeTerminalSend("tool-start")) return;
853
851
  await emitFullSegment(formatToolStartSummary(payload));
854
852
  }
855
853
  : undefined,
856
- onToolResult: splitFullOutput
854
+ onToolResult: outputVisibility === "full"
857
855
  ? async (payload: ReplyPayload) => {
858
856
  if (consumeTerminalSend("tool-result")) return;
859
857
  const text = resolvePayloadText(payload);
@@ -861,38 +859,38 @@ export function createOpenclawClawlingReplyDispatcher(options: ReplyDispatcherOp
861
859
  await emitFullRuntimeText("tool result", text, resolveOutboundMediaUrls(payload).filter(Boolean));
862
860
  }
863
861
  : undefined,
864
- onItemEvent: splitFullOutput
862
+ onItemEvent: outputVisibility === "full"
865
863
  ? async (payload: Record<string, unknown>) => {
866
864
  if (consumeTerminalSend("item-event")) return;
867
865
  if (isToolProgressItem(payload)) return;
868
866
  await emitFullRuntimeText("progress", summarizeProgressPayload(payload));
869
867
  }
870
868
  : undefined,
871
- onPlanUpdate: splitFullOutput
869
+ onPlanUpdate: outputVisibility === "full"
872
870
  ? async (payload: Record<string, unknown>) => {
873
871
  if (consumeTerminalSend("plan-update")) return;
874
872
  await emitFullRuntimeText("plan", summarizeProgressPayload(payload));
875
873
  }
876
874
  : undefined,
877
- onCommandOutput: splitFullOutput
875
+ onCommandOutput: outputVisibility === "full"
878
876
  ? async (payload: Record<string, unknown>) => {
879
877
  if (consumeTerminalSend("command-output")) return;
880
878
  await emitFullSegment(formatCommandOutputSummary(payload));
881
879
  }
882
880
  : undefined,
883
- onPatchSummary: splitFullOutput
881
+ onPatchSummary: outputVisibility === "full"
884
882
  ? async (payload: Record<string, unknown>) => {
885
883
  if (consumeTerminalSend("patch-summary")) return;
886
884
  await emitFullSegment(formatPatchSummary(payload));
887
885
  }
888
886
  : undefined,
889
- onCompactionStart: splitFullOutput
887
+ onCompactionStart: outputVisibility === "full"
890
888
  ? async () => {
891
889
  if (consumeTerminalSend("compaction-start")) return;
892
890
  await emitFullSegment("[compaction] started");
893
891
  }
894
892
  : undefined,
895
- onCompactionEnd: splitFullOutput
893
+ onCompactionEnd: outputVisibility === "full"
896
894
  ? async () => {
897
895
  if (consumeTerminalSend("compaction-end")) return;
898
896
  await emitFullSegment("[compaction] finished");