
















@@ -8,6 +8,7 @@ import {
88normalizeChannelProgressDraftLineIdentity,
99resolveChannelProgressDraftMaxLines,
1010resolveChannelStreamingBlockEnabled,
11+resolveChannelStreamingProgressCommentary,
1112resolveChannelStreamingPreviewToolProgress,
1213resolveChannelStreamingSuppressDefaultToolProgressMessages,
1314} from "openclaw/plugin-sdk/channel-outbound";
@@ -81,6 +82,8 @@ export function createDiscordDraftPreviewController(params: {
8182let finalReplyDelivered = false;
8283const previewToolProgressEnabled =
8384Boolean(draftStream) && resolveChannelStreamingPreviewToolProgress(params.discordConfig);
85+const commentaryProgressEnabled =
86+Boolean(draftStream) && resolveChannelStreamingProgressCommentary(params.discordConfig);
8487const suppressDefaultToolProgressMessages =
8588Boolean(draftStream) &&
8689resolveChannelStreamingSuppressDefaultToolProgressMessages(params.discordConfig, {
@@ -119,6 +122,34 @@ export function createDiscordDraftPreviewController(params: {
119122onStart: () => renderProgressDraft({ flush: true }),
120123});
121124125+const clearProgressDraftLine = async (lineId: string) => {
126+const nextLines = previewToolProgressLines.filter(
127+(line) => typeof line !== "object" || line.id?.trim() !== lineId,
128+);
129+if (nextLines.length === previewToolProgressLines.length) {
130+return;
131+}
132+previewToolProgressLines = nextLines;
133+if (!progressDraftGate.hasStarted) {
134+return;
135+}
136+const previewText = formatChannelProgressDraftText({
137+entry: params.discordConfig,
138+lines: previewToolProgressLines,
139+seed: progressSeed,
140+});
141+if (previewText) {
142+await renderProgressDraft();
143+return;
144+}
145+lastPartialText = "";
146+draftText = "";
147+hasStreamedMessage = false;
148+if (draftStream?.messageId()) {
149+await draftStream.deleteCurrentMessage();
150+}
151+};
152+122153const resetProgressState = () => {
123154lastPartialText = "";
124155draftText = "";
@@ -140,6 +171,7 @@ export function createDiscordDraftPreviewController(params: {
140171return {
141172 draftStream,
142173 previewToolProgressEnabled,
174+ commentaryProgressEnabled,
143175 suppressDefaultToolProgressMessages,
144176get isProgressMode() {
145177return discordStreamMode === "progress";
@@ -268,6 +300,38 @@ export function createDiscordDraftPreviewController(params: {
268300await renderProgressDraft();
269301}
270302},
303+async pushCommentaryProgress(text?: string, options?: { itemId?: string }) {
304+if (!draftStream || discordStreamMode !== "progress" || !commentaryProgressEnabled) {
305+return;
306+}
307+if (finalReplyStarted || finalReplyDelivered) {
308+return;
309+}
310+const itemId = options?.itemId?.trim();
311+if (!text && !itemId) {
312+return;
313+}
314+const normalized = normalizeCommentaryProgressText(text ?? "");
315+const lineId = itemId ? `commentary:${itemId}` : normalized ? `commentary:${normalized}` : "";
316+if (!normalized) {
317+if (lineId) {
318+await clearProgressDraftLine(lineId);
319+}
320+return;
321+}
322+const line: ChannelProgressDraftLine = {
323+id: lineId,
324+kind: "item",
325+text: normalized,
326+label: "Commentary",
327+prefix: false,
328+};
329+previewToolProgressLines = mergeChannelProgressDraftLine(previewToolProgressLines, line, {
330+maxLines: resolveChannelProgressDraftMaxLines(params.discordConfig),
331+});
332+await progressDraftGate.startNow();
333+await renderProgressDraft();
334+},
271335resolvePreviewFinalText(text?: string) {
272336if (typeof text !== "string") {
273337return undefined;
@@ -405,6 +469,24 @@ function normalizeReasoningProgressLine(text: string): string {
405469.trim();
406470}
407471472+function normalizeCommentaryProgressText(text: string): string {
473+const cleaned = stripInlineDirectiveTagsForDelivery(text).text.trim();
474+if (!cleaned || isSilentCommentaryProgressText(cleaned)) {
475+return "";
476+}
477+return cleaned
478+.split(/\r?\n/u)
479+.map((line) => line.replace(/\s+/g, " ").trim())
480+.filter(Boolean)
481+.map((line) => `_${line}_`)
482+.join("\n");
483+}
484+485+function isSilentCommentaryProgressText(text: string): boolean {
486+const normalized = text.replace(/^[\s*_`~]+|[\s*_`~]+$/gu, "").trim();
487+return /^NO_REPLY$/iu.test(normalized);
488+}
489+408490function mergeReasoningProgressText(
409491current: string,
410492incoming: string,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。