惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
爱范儿
爱范儿
P
Proofpoint News Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Tailwind CSS Blog
J
Java Code Geeks
宝玉的分享
宝玉的分享
Jina AI
Jina AI
B
Blog
N
Netflix TechBlog - Medium
Recent Announcements
Recent Announcements
aimingoo的专栏
aimingoo的专栏
腾讯CDC
C
Check Point Blog
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
博客园 - Franky
罗磊的独立博客
B
Blog RSS Feed
WordPress大学
WordPress大学
小众软件
小众软件
博客园 - 叶小钗
M
MIT News - Artificial intelligence
GbyAI
GbyAI

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix: keep progress draft labels visible · openclaw/opencl...
shakkernerd · 2026-05-08 · via Recent Commits to openclaw:main
Original file line numberDiff line numberDiff line change

@@ -12,7 +12,7 @@ Docs: https://docs.openclaw.ai

1212

- Control UI: read the Quick Settings exec policy badge from `tools.exec.security` instead of the non-schema `agents.defaults.exec.security` path, so configured `full`/`deny` values render accurately. Fixes #78311. Thanks @FriedBack.

1313

- Control UI/usage: add transcript-backed historical lineage rollups for rotated logical sessions, with current-instance vs historical-lineage scope controls and long-range presets so usage history stays visible after restarts and updates. Fixes #50701. Thanks @dev-gideon-llc and @BunsDev.

1414

- Agents/failover: harden state-aware lane suspension by persisting quota resume transitions, restoring configured lane concurrency, preserving non-quota failure reasons, and exporting model failover events through diagnostics OTLP. Thanks @BunsDev.

15-

- Channels/streaming: make progress draft labels scroll away with other progress lines, render structured tool rows as compact emoji/title/details, show web-search queries from provider-native argument shapes, and skip empty Discord apply-patch starts until a patch summary exists. (#79146)

15+

- Channels/streaming: render structured tool rows as compact emoji/title/details, show web-search queries from provider-native argument shapes, and skip empty Discord apply-patch starts until a patch summary exists. (#79146)

1616

- Workspace/oc-path: add the `oc://` addressing substrate (`src/oc-path/`) — a universal, kind-dispatched path scheme for addressing leaves and nodes inside markdown, jsonc, jsonl, and yaml workspace files, with `parseOcPath`/`formatOcPath`, per-kind `parseXxx`/`emitXxx`, universal `resolveOcPath`/`setOcPath`/`findOcPaths` verbs, the `__OPENCLAW_REDACTED__` sentinel emit guard, and the new `openclaw path resolve|find|set|validate|emit` CLI for shell-level inspection and surgical edits. Implements #78051. (#78678) Thanks @giodl73-repo.

1717

- Runtime/performance: avoid full-array sorting while auto-selecting providers, resolving supported thinking levels, picking node last-seen timestamps, and extracting Codex usage-limit messages. Thanks @shakkernerd.

1818

- Plugins/doctor: avoid full-array sorting while selecting ClawHub search/archive results and bounded dreaming doctor entries. Thanks @shakkernerd.

@@ -185,6 +185,7 @@ Docs: https://docs.openclaw.ai

185185

### Fixes

186186
187187

- Agents/compaction: keep the recent tail after manual `/compact` when Pi returns an empty or no-op compaction summary, preventing blank checkpoints from replacing the live context.

188+

- Channels/streaming: keep progress draft labels visible above the last `streaming.progress.maxLines` progress rows instead of counting the label against the rolling line limit. Thanks @shakkernerd.

188189

- fix(discord): gate user allowlist name resolution [AI]. (#79002) Thanks @pgondhi987.

189190

- fix(msteams): gate startup user allowlist resolution [AI]. (#79003) Thanks @pgondhi987.

190191

- Harden macOS shell wrapper allowlist parsing [AI]. (#78518) Thanks @pgondhi987.

Original file line numberDiff line numberDiff line change

@@ -662,7 +662,7 @@ Default slash command settings:

662662

</Accordion>

663663
664664

<Accordion title="Live stream preview">

665-

OpenClaw can stream draft replies by sending a temporary message and editing it as text arrives. `channels.discord.streaming` takes `off` | `partial` | `block` | `progress` (default). `progress` keeps one editable status draft and updates it with tool progress until final delivery; the shared starter label is a rolling line, so it scrolls away like the rest once enough work appears. `streamMode` is a legacy runtime alias. Run `openclaw doctor --fix` to rewrite persisted config to the canonical key.

665+

OpenClaw can stream draft replies by sending a temporary message and editing it as text arrives. `channels.discord.streaming` takes `off` | `partial` | `block` | `progress` (default). `progress` keeps one editable status draft and updates it with tool progress until final delivery; the shared starter label stays visible while `streaming.progress.maxLines` limits the rolling progress lines below it. `streamMode` is a legacy runtime alias. Run `openclaw doctor --fix` to rewrite persisted config to the canonical key.

666666
667667

Set `channels.discord.streaming.mode` to `off` to disable Discord preview edits. If Discord block streaming is explicitly enabled, OpenClaw skips the preview stream to avoid double-streaming.

668668
Original file line numberDiff line numberDiff line change

@@ -57,9 +57,10 @@ A progress draft has two parts:

5757

| Progress lines | Compact run updates using the same tool icons and detail formatter as verbose output. |

5858
5959

The label appears after the agent starts meaningful work and either remains busy

60-

for five seconds or emits a second work event. It is part of the rolling progress

61-

line list, so the starter status scrolls away once enough concrete work appears.

62-

Plain text-only replies do not show a progress draft. Progress lines are added

60+

for five seconds or emits a second work event. It stays visible while the agent

61+

is still working; `streaming.progress.maxLines` limits only the rolling progress

62+

lines below the label. In other words, progress drafts render as `label + last N

63+

progress lines`. Plain text-only replies do not show a progress draft. Progress lines are added

6364

only when the agent emits useful work updates, for example `🛠️ Bash: run tests`,

6465

`🔎 Web Search: for "discord edit message"`, or `✍️ Write: to /tmp/file`.

6566

By default they use the same compact explain mode as `/verbose`; set

Original file line numberDiff line numberDiff line change

@@ -1656,7 +1656,7 @@ describe("processDiscordMessage draft streaming", () => {

16561656

expect(draftStream.update).toHaveBeenCalledWith("Shelling\n🛠️ Exec\n• done");

16571657

});

16581658
1659-

it("keeps Discord progress labels as rolling lines", async () => {

1659+

it("keeps Discord progress labels visible above rolling lines", async () => {

16601660

const draftStream = createMockDraftStreamForTest();

16611661
16621662

dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {

@@ -1680,7 +1680,7 @@ describe("processDiscordMessage draft streaming", () => {

16801680
16811681

await runProcessDiscordMessage(ctx);

16821682
1683-

expect(draftStream.update).toHaveBeenCalledWith("🧩 First\n🧩 Second\n🧩 Third");

1683+

expect(draftStream.update).toHaveBeenCalledWith("Clawing...\n🧩 First\n🧩 Second\n🧩 Third");

16841684

});

16851685
16861686

it("skips empty apply_patch starts and renders the patch summary", async () => {

Original file line numberDiff line numberDiff line change

@@ -320,7 +320,9 @@ describe("createTeamsReplyStreamController", () => {

320320
321321

expect(ctrl.shouldSuppressDefaultToolProgressMessages()).toBe(true);

322322

expect(ctrl.shouldStreamPreviewToolProgress()).toBe(true);

323-

expect(streamInstances[0]?.sendInformativeUpdate).toHaveBeenLastCalledWith("- tool: exec");

323+

expect(streamInstances[0]?.sendInformativeUpdate).toHaveBeenLastCalledWith(

324+

"Working\n- tool: exec",

325+

);

324326

});

325327
326328

it("suppresses Teams default progress messages without stream lines when tool progress is disabled", async () => {

Original file line numberDiff line numberDiff line change

@@ -354,9 +354,8 @@ vi.mock("openclaw/plugin-sdk/channel-streaming", () => ({

354354

const label = params.entry?.streaming?.progress?.label;

355355

const maxLines = params.entry?.streaming?.progress?.maxLines ?? 8;

356356

const formatLine = params.formatLine ?? ((line: string) => line);

357-

const lines = [

358-

label === false ? undefined : (label ?? "Thinking"),

359-

...params.lines.map((line) => {

357+

const progressLines = params.lines

358+

.map((line) => {

360359

const text =

361360

typeof line === "string"

362361

? line

@@ -367,10 +366,12 @@ vi.mock("openclaw/plugin-sdk/channel-streaming", () => ({

367366

: line.text;

368367

const formatted = formatLine(text);

369368

return /^\p{Extended_Pictographic}/u.test(text) ? formatted : `• ${formatted}`;

370-

}),

371-

]

369+

})

372370

.filter((line): line is string => Boolean(line))

373371

.slice(-maxLines);

372+

const lines = [label === false ? undefined : (label ?? "Thinking"), ...progressLines].filter(

373+

(line): line is string => Boolean(line),

374+

);

374375

return lines.join("\n");

375376

},

376377

formatChannelProgressDraftLine: (params: {

@@ -827,6 +828,7 @@ describe("dispatchPreparedSlackMessage preview fallback", () => {

827828
828829

expect(draftStream.update).toHaveBeenLastCalledWith(

829830

[

831+

"Shelling",

830832

"• step 1",

831833

"• step 2",

832834

"• step 3",

Original file line numberDiff line numberDiff line change

@@ -211,24 +211,36 @@ describe("channel-streaming", () => {

211211

lines: [" tool: read ", "patch applied", "tests done"],

212212

formatLine: (line) => `\`${line}\``,

213213

}),

214-

).toBe("• `patch applied`\n• `tests done`");

214+

).toBe("Shelling\n• `patch applied`\n• `tests done`");

215215

expect(

216216

formatChannelProgressDraftText({

217217

entry,

218218

lines: ["🛠️ Exec", "plain update"],

219219

}),

220-

).toBe("🛠️ Exec\n• plain update");

220+

).toBe("Shelling\n🛠️ Exec\n• plain update");

221221

});

222222
223-

it("renders progress labels as rolling lines", () => {

223+

it("keeps progress labels outside the rolling line limit", () => {

224+

const entry = { streaming: { progress: { label: "Working", maxLines: 1 } } };

225+
226+

expect(

227+

formatChannelProgressDraftText({

228+

entry,

229+

lines: ["tool: search", "tool: exec"],

230+

bullet: "-",

231+

}),

232+

).toBe("Working\n- tool: exec");

233+

});

234+
235+

it("keeps progress labels visible with bounded rolling lines", () => {

224236

const entry = { streaming: { progress: { label: "Shelling", maxLines: 3 } } };

225237
226238

expect(

227239

formatChannelProgressDraftText({

228240

entry,

229241

lines: ["🛠️ Exec", "📖 Read", "🩹 Patch"],

230242

}),

231-

).toBe("🛠️ Exec\n📖 Read\n🩹 Patch");

243+

).toBe("Shelling\n🛠️ Exec\n📖 Read\n🩹 Patch");

232244

});

233245
234246

it("renders structured progress lines with compact details", () => {

Original file line numberDiff line numberDiff line change

@@ -792,25 +792,21 @@ export function formatChannelProgressDraftText(params: {

792792

const maxLines = resolveChannelProgressDraftMaxLines(params.entry);

793793

const formatLine = params.formatLine ?? ((line: string) => line);

794794

const bullet = params.bullet ?? "•";

795-

const rawLines: Array<string | ChannelProgressDraftLine | { draftLabel: string }> = label

796-

? [{ draftLabel: label }, ...params.lines]

797-

: params.lines;

798-

const lines = rawLines

795+

const labelLine = label

796+

? compactChannelProgressDraftLine(label, DEFAULT_PROGRESS_DRAFT_MAX_LINE_CHARS)

797+

: "";

798+

const progressLines = params.lines

799799

.map((line) => {

800-

const isLabelLine = typeof line === "object" && line !== null && "draftLabel" in line;

801-

const rawText = isLabelLine

802-

? line.draftLabel

803-

: typeof line === "string"

804-

? line

805-

: getProgressDraftLineText(line);

800+

const rawText = typeof line === "string" ? line : getProgressDraftLineText(line);

806801

const text = compactChannelProgressDraftLine(rawText, DEFAULT_PROGRESS_DRAFT_MAX_LINE_CHARS);

807-

return text ? { text, isLabelLine } : undefined;

802+

return text || undefined;

808803

})

809-

.filter((line): line is { text: string; isLabelLine: boolean } => Boolean(line))

804+

.filter((line): line is string => Boolean(line))

810805

.slice(-maxLines)

811-

.map(({ text, isLabelLine }) => {

812-

const formatted = isLabelLine ? text : formatLine(text);

813-

return !isLabelLine && shouldPrefixProgressLine(text) ? `${bullet} ${formatted}` : formatted;

806+

.map((text) => {

807+

const formatted = formatLine(text);

808+

return shouldPrefixProgressLine(text) ? `${bullet} ${formatted}` : formatted;

814809

});

815-

return lines.filter((line): line is string => Boolean(line)).join("\n");

810+

const lines = labelLine ? [labelLine, ...progressLines] : progressLines;

811+

return lines.join("\n");

816812

}