fix: compact progress draft lines

This commit is contained in:
Peter Steinberger
2026-05-04 03:50:11 +01:00
parent f632f5e60b
commit a3c36a0931
6 changed files with 69 additions and 5 deletions

View File

@@ -11,6 +11,7 @@ Docs: https://docs.openclaw.ai
### Changes
- Channels/streaming: add unified `streaming.mode: "progress"` drafts with auto single-word status labels and shared progress configuration across Discord, Telegram, Matrix, Slack, and Microsoft Teams.
- Channels/streaming: cap progress-draft tool lines by default so edited progress boxes avoid jumpy reflow from long wrapped lines.
- Agents/verbose: use compact explain-mode tool summaries for `/verbose` and progress drafts by default, with `agents.defaults.toolProgressDetail: "raw"` and per-agent overrides for debugging raw command/detail output.
- Agents/commands: add `/steer <message>` for queue-independent steering of the active current-session run without starting a new turn when the session is idle. (#76934)
- Tools/BTW: add `/side` as a text and native slash-command alias for `/btw` side questions.

View File

@@ -1,4 +1,4 @@
3e7cbffbe3849b5201716f359dde9089d61d618c1a4206255c20887a855d85a9 config-baseline.json
ac95b4ab62408454636ce559e6d023df3c29b8b936b3aa4dde37779d29a5a099 config-baseline.json
31ec333df9f8b92c7656ac7107cecd5860dd02e08f7e18c7c674dc47a8811baa config-baseline.core.json
655d1309b70505e73198df20c5088784290b33098efd42027d3c09beeb3704a7 config-baseline.channel.json
055fae0d0067a751dc10125af7421da45633f73519c94c982d02b0c4eb2bdf67 config-baseline.plugin.json
9458dc89aa13dd07d83f69d943535099a96e8278eb7ac8ae5cf2f713631592f7 config-baseline.plugin.json

View File

@@ -1,2 +1,2 @@
0dd4f5abaf72f0d6b3fe5777cbf16c7a8c8052eece17436dc0ac2809b0ea27de plugin-sdk-api-baseline.json
2c2170cf2f1193f7dbecdef3ccd1b601992407e3d99863d1aa13cb1817c238fd plugin-sdk-api-baseline.jsonl
701356478634a8f3e71f941ed21a00e0456d947d287edcafb56231013b27a057 plugin-sdk-api-baseline.json
ed17426dd5e9db4b83db77162e7490eee3c0439170c1a9d1e84c01d7027d580c plugin-sdk-api-baseline.jsonl

View File

@@ -217,6 +217,12 @@ Limit how many lines stay visible:
}
```
Progress lines are compacted automatically to reduce chat-bubble reflow while the draft is edited.
OpenClaw truncates long progress lines by default so repeated draft edits do not
wrap differently on every update. The prefix stays readable, and long details
such as paths or raw commands are shortened with an ellipsis.
Keep the single progress draft but hide tool and task lines:
```json5

View File

@@ -186,6 +186,16 @@ describe("channel-streaming", () => {
).toBe("Shelling\n🛠 Exec\n• plain update");
});
it("bounds progress draft line length to reduce edit reflow", () => {
expect(
formatChannelProgressDraftText({
entry: { streaming: { progress: { label: "Shelling" } } },
lines: ["x".repeat(80)],
formatLine: (line) => `\`${line}\``,
}),
).toBe(`Shelling\n• \`${"x".repeat(71)}\``);
});
it("formats progress draft lines with shared tool display labels", () => {
expect(
formatChannelProgressDraftLine({

View File

@@ -110,6 +110,7 @@ export const DEFAULT_PROGRESS_DRAFT_LABELS = [
] as const;
export const DEFAULT_PROGRESS_DRAFT_INITIAL_DELAY_MS = 5_000;
const DEFAULT_PROGRESS_DRAFT_MAX_LINE_CHARS = 72;
const NON_WORK_PROGRESS_TOOL_NAMES = new Set([
"message",
@@ -537,6 +538,52 @@ export function resolveChannelProgressDraftMaxLines(
return configured && configured > 0 ? configured : defaultValue;
}
function sliceCodePoints(value: string, start: number, end?: number): string {
return Array.from(value).slice(start, end).join("");
}
function compactProgressLineDetail(detail: string, maxChars: number): string {
const chars = Array.from(detail);
if (chars.length <= maxChars) {
return detail;
}
if (maxChars <= 1) {
return "…";
}
const keepStart = Math.max(1, Math.ceil((maxChars - 1) * 0.45));
const keepEnd = Math.max(1, maxChars - keepStart - 1);
const rawStart = chars.slice(0, keepStart).join("").trimEnd();
const start =
rawStart.length > 8 && /\s+\S+$/.test(rawStart) ? rawStart.replace(/\s+\S+$/, "") : rawStart;
return `${start}${chars.slice(-keepEnd).join("").trimStart()}`;
}
function compactChannelProgressDraftLine(line: string, maxChars: number): string {
const normalized = line.replace(/\s+/g, " ").trim();
if (!normalized) {
return "";
}
const chars = Array.from(normalized);
if (chars.length <= maxChars) {
return normalized;
}
if (maxChars <= 1) {
return "…";
}
const splitIndex = normalized.indexOf(": ");
if (splitIndex > 0) {
const prefix = normalized.slice(0, splitIndex + 2);
const prefixChars = Array.from(prefix).length;
const detailLimit = maxChars - prefixChars;
if (detailLimit >= 8) {
return `${prefix}${compactProgressLineDetail(normalized.slice(splitIndex + 2), detailLimit)}`;
}
}
return `${sliceCodePoints(normalized, 0, maxChars - 1).trimEnd()}`;
}
export function formatChannelProgressDraftText(params: {
entry?: StreamingCompatEntry | null;
lines: string[];
@@ -554,7 +601,7 @@ export function formatChannelProgressDraftText(params: {
const formatLine = params.formatLine ?? ((line: string) => line);
const bullet = params.bullet ?? "•";
const lines = params.lines
.map((line) => line.replace(/\s+/g, " ").trim())
.map((line) => compactChannelProgressDraftLine(line, DEFAULT_PROGRESS_DRAFT_MAX_LINE_CHARS))
.filter((line) => line.length > 0)
.slice(-maxLines)
.map((line) =>