fix(channels): balance compact progress markdown

This commit is contained in:
Vincent Koc
2026-05-03 19:54:43 -07:00
parent bc924889be
commit 8846fe0998
3 changed files with 34 additions and 2 deletions

View File

@@ -66,6 +66,7 @@ Docs: https://docs.openclaw.ai
- Agents/messaging: deliver distinct final commentary after same-target `message` tool sends while still deduping text/media already sent by the tool, so short closing remarks are no longer silently dropped. Fixes #76915. Thanks @hclsys.
- Agents/messaging: preserve string thread IDs when matching message-tool reply dedupe routes, avoiding precision loss on numeric-looking topic IDs before channel plugin comparison. Thanks @vincentkoc.
- Channels/streaming: honor `agents.defaults.toolProgressDetail: "raw"` in Slack, Discord, Telegram, Matrix, and Microsoft Teams progress drafts, so tool-start lines include raw command/detail output when debugging. Thanks @vincentkoc.
- Channels/streaming: strip unmatched inline-code backticks from compacted raw progress draft lines, avoiding stray markdown markers after long command details are shortened. Thanks @vincentkoc.
- Discord/Slack/Mattermost: align draft preview tool-progress config help with the runtime behavior that hides interim tool updates when `streaming.preview.toolProgress` is false. Thanks @vincentkoc.
- Feishu: use the shared channel progress formatter for streaming-card tool status lines, including raw command/detail output and message-tool filtering. Thanks @vincentkoc.
- Mattermost: use the shared progress draft formatter for tool status previews, including raw command/detail output when `agents.defaults.toolProgressDetail: "raw"` is enabled. Thanks @vincentkoc.

View File

@@ -196,6 +196,28 @@ describe("channel-streaming", () => {
).toBe(`Shelling\n• \`${"x".repeat(71)}\``);
});
it("keeps compacted raw progress lines from leaking unmatched markdown backticks", () => {
const line = formatChannelProgressDraftLine(
{
event: "tool",
name: "exec",
args: {
command:
"node scripts/check-something-with-a-very-long-path /tmp/openclaw/some/really/deep/path/that/keeps/going/and/going/index.ts --flag value",
},
},
{ detailMode: "raw" },
);
const text = formatChannelProgressDraftText({
entry: { streaming: { progress: { label: "Shelling" } } },
lines: [line ?? ""],
});
expect(text).toBe("Shelling\n🛠 Exec: run node script…that/keeps/going/and/going/index…");
expect(text.match(/`/g) ?? []).toHaveLength(0);
});
it("formats progress draft lines with shared tool display labels", () => {
expect(
formatChannelProgressDraftLine({

View File

@@ -558,6 +558,11 @@ function compactProgressLineDetail(detail: string, maxChars: number): string {
return `${start}${chars.slice(-keepEnd).join("").trimStart()}`;
}
function removeUnbalancedInlineBackticks(value: string): string {
const backtickCount = Array.from(value).filter((char) => char === "`").length;
return backtickCount % 2 === 1 ? value.replaceAll("`", "") : value;
}
function compactChannelProgressDraftLine(line: string, maxChars: number): string {
const normalized = line.replace(/\s+/g, " ").trim();
if (!normalized) {
@@ -577,11 +582,15 @@ function compactChannelProgressDraftLine(line: string, maxChars: number): string
const prefixChars = Array.from(prefix).length;
const detailLimit = maxChars - prefixChars;
if (detailLimit >= 8) {
return `${prefix}${compactProgressLineDetail(normalized.slice(splitIndex + 2), detailLimit)}`;
return removeUnbalancedInlineBackticks(
`${prefix}${compactProgressLineDetail(normalized.slice(splitIndex + 2), detailLimit)}`,
);
}
}
return `${sliceCodePoints(normalized, 0, maxChars - 1).trimEnd()}`;
return removeUnbalancedInlineBackticks(
`${sliceCodePoints(normalized, 0, maxChars - 1).trimEnd()}`,
);
}
export function formatChannelProgressDraftText(params: {