openclaw - 💡(How to fix) Fix Design: add a channel-agnostic progress/status lane and a single source of truth for progress vs final delivery [1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#48963Fetched 2026-04-08 00:50:26
View on GitHub
Comments
1
Participants
1
Timeline
1
Reactions
0
Participants
Timeline (top)
commented ×1

Tool-heavy turns on channel integrations currently lack a source-level abstraction for progress/status vs final reply ownership.

As a result, channel adapters (especially Discord) end up inventing their own semantics for:

  • pre-tool narration
  • in-progress status
  • tool-result visibility
  • final reply ownership
  • cleanup after completion

This leads to a recurring class of bugs that look different on the surface, but appear to share the same missing abstraction.

Root Cause

What users often want is not necessarily “true token streaming”.

What they actually want is:

  1. visible progress while a tool-heavy turn is running
  2. a clean final message when the turn completes
  3. no duplicate status bubbles or out-of-order final content

Right now adapters are forced to choose between these imperfect tradeoffs locally.

Fix Action

Fix / Workaround

  • a Discord-only feature flag without shared semantics
  • another narrow partial tuning knob by itself
  • a direct runtime bundle patch as upstream solution
  • “true streaming” for every channel at any cost

If yes, that seems like a better long-term path than continuing to patch Discord-specific ownership behavior one symptom at a time.

Code Example

Please use the exec tool to run `sleep 2; ls -1 | head -5`, then return a 6-line fenced code block and one-sentence summary. If you did not call the tool, reply TOOL_NOT_CALLED.
RAW_BUFFERClick to expand / collapse

Summary

Tool-heavy turns on channel integrations currently lack a source-level abstraction for progress/status vs final reply ownership.

As a result, channel adapters (especially Discord) end up inventing their own semantics for:

  • pre-tool narration
  • in-progress status
  • tool-result visibility
  • final reply ownership
  • cleanup after completion

This leads to a recurring class of bugs that look different on the surface, but appear to share the same missing abstraction.

Why this matters

What users often want is not necessarily “true token streaming”.

What they actually want is:

  1. visible progress while a tool-heavy turn is running
  2. a clean final message when the turn completes
  3. no duplicate status bubbles or out-of-order final content

Right now adapters are forced to choose between these imperfect tradeoffs locally.

Observed symptoms

On Discord tool-heavy turns, depending on adapter strategy and timing, we observed variants of:

  • extra intermediate narration messages before tool calls
  • duplicate status messages at tool start
  • preview/progress ownership racing with final reply ownership
  • final reply competing with in-progress preview instead of having a shared handoff model
  • “clean channel after completion” requiring adapter-local cleanup logic

This showed up across multiple tool paths (exec, web_search, web_fetch) and across more than one Discord channel, so this does not look like a single-channel one-off.

Minimal repro shape

  1. Use a Discord channel with tool-heavy turns.
  2. Keep Discord preview/progress enabled (streaming: partial or adjacent live-preview behavior).
  3. Send a request that reliably produces:
    • assistant text before a tool call
    • one or more tool calls/results
    • a final assistant answer
  4. Observe that adapters must currently decide locally how progress and final ownership should work.

One simple example:

Please use the exec tool to run `sleep 2; ls -1 | head -5`, then return a 6-line fenced code block and one-sentence summary. If you did not call the tool, reply TOOL_NOT_CALLED.

Actual

Today, the system has enough adjacent knobs to move the symptoms around, but not enough shared structure to solve them cleanly.

Examples:

  • suppressing intermediate text can reduce spam, but hides useful progress
  • keeping preview visible can improve liveness, but then final ownership becomes adapter-specific
  • adding an explicit status message lane locally can work, but can also duplicate status unless preview-based status writing is also disabled
  • cleaning up intermediate status after final delivery works, but again requires adapter-local ownership logic

In other words: the adapter is doing reply assembly work that probably belongs upstream of the adapter.

Expected

A source-level abstraction should exist for:

  • progress/status lane
  • final reply lane
  • ownership / handoff rules between them
  • cleanup policy after final delivery

Channel adapters should consume that abstraction instead of redefining progress/final semantics themselves.

Proposed design direction

Introduce a channel-agnostic progress/status lane in the reply assembly layer, and make progress/final delivery share a single source of truth.

That would let channels choose rendering policy without inventing ownership policy.

For example, adapters could choose among strategies like:

  • hide progress entirely
  • render progress as edit-in-place preview
  • render progress as a transient status message
  • keep or auto-clean progress after final delivery

But the adapter should not have to decide from scratch:

  • whether pre-tool text is progress or final
  • whether tool-result visibility belongs to preview or final
  • whether final replaces progress or is separate
  • when intermediate status should be withdrawn

Why this is not just a duplicate of nearby issues

There are several adjacent issues/PRs, but they look like symptoms or narrow slices of the same underlying gap:

  • #29649 asks for suppressing intermediate tool-loop text entirely
  • #14479 focuses on ordering problems between process blocks and final reply
  • #22258 focuses on duplicate/fragmented messages during tool execution
  • #31679 focuses on streaming=off still splitting a single logical response into multiple Discord messages
  • #42745 bridges ACP thread live output into Discord draft preview, which is useful but still channel/path-specific
  • #45320 exposes preview boundary rotation behavior for Discord partial

Those are all valuable, but none of them seem to define the shared source-level abstraction directly.

Non-goals

This issue is not asking for:

  • a Discord-only feature flag without shared semantics
  • another narrow partial tuning knob by itself
  • a direct runtime bundle patch as upstream solution
  • “true streaming” for every channel at any cost

Concrete question for maintainers

Would the project accept a design direction where reply assembly exposes a shared progress/status lane plus final lane, and channel adapters only choose how to render/retain/clean them?

If yes, that seems like a better long-term path than continuing to patch Discord-specific ownership behavior one symptom at a time.

extent analysis

Fix Plan

To address the issue, we will introduce a channel-agnostic progress/status lane in the reply assembly layer. This will provide a single source of truth for progress and final delivery, allowing channels to choose their rendering policy without inventing ownership policy.

Step-by-Step Solution

  1. Introduce a Progress class: Create a new class to represent the progress/status lane, which will hold the current progress state and provide methods to update it.
  2. Modify the reply assembly layer: Update the reply assembly layer to use the Progress class and provide a shared source of truth for progress and final delivery.
  3. Update channel adapters: Modify channel adapters to consume the Progress class and choose their rendering policy, such as hiding progress, rendering progress as edit-in-place preview, or keeping progress after final delivery.

Example Code

# progress.py
class Progress:
    def __init__(self):
        self.status = None
        self.final_reply = None

    def update_status(self, status):
        self.status = status

    def set_final_reply(self, final_reply):
        self.final_reply = final_reply

# reply_assembly.py
class ReplyAssembly:
    def __init__(self):
        self.progress = Progress()

    def assemble_reply(self, progress_update, final_reply):
        self.progress.update_status(progress_update)
        self.progress.set_final_reply(final_reply)
        return self.progress

# discord_adapter.py
class DiscordAdapter:
    def __init__(self):
        self.rendering_policy = "edit-in-place-preview"

    def render_progress(self, progress):
        if self.rendering_policy == "edit-in-place-preview":
            # Render progress as edit-in-place preview
            pass
        elif self.rendering_policy == "hide-progress":
            # Hide progress
            pass
        # ...

Verification

To verify that the fix worked, test the following scenarios:

  • Send a request that produces a tool-heavy turn with progress updates and a final reply.
  • Verify that the progress updates are rendered correctly according to the chosen rendering policy.
  • Verify that the final reply is delivered correctly and replaces the progress updates if necessary.

Extra Tips

  • Make sure to handle edge cases, such as when the progress updates are empty or when the final reply is not provided.
  • Consider adding logging and monitoring to track the progress and final delivery of tool-heavy turns.
  • Review the code changes to ensure that they are consistent with the project's coding standards and best practices.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Design: add a channel-agnostic progress/status lane and a single source of truth for progress vs final delivery [1 comments, 1 participants]