openclaw - 💡(How to fix) Fix [Bug]: Thinking stream not forwarded via WebSocket agent events during streaming [1 comments, 2 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#51505Fetched 2026-04-08 01:10:19
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
2
Timeline (top)
labeled ×2commented ×1mentioned ×1subscribed ×1

When extended thinking is enabled (Think: high, Reasoning: stream, model reasoning: true), the gateway stores thinking content in the transcript (visible via chat.history) but does not emit stream: "thinking" agent events via WebSocket during streaming, making real-time thinking display impossible for WebChat frontends.

Root Cause

When extended thinking is enabled (Think: high, Reasoning: stream, model reasoning: true), the gateway stores thinking content in the transcript (visible via chat.history) but does not emit stream: "thinking" agent events via WebSocket during streaming, making real-time thinking display impossible for WebChat frontends.

Code Example

{
  "models": {
    "mode": "merge",
    "providers": {
      "custom-anthropic": {
        "baseUrl": "xxxx",
        "api": "anthropic-messages",
        "models": [
          {
            "id": "claude-opus-4-6",
            "name": "claude-opus-4-6 (Custom Provider)",
            "reasoning": true
          }
        ]
      }
    }
  }
}

---

### WebSocket agent events (excerpt — all stream values during a full response)


stream: "lifecycle"  (phase: startedAt)
stream: "assistant"  (dataKeys: [text, delta])  ← repeated for all content chunks
stream: "assistant"  (dataKeys: [text, delta])
stream: "assistant"  (dataKeys: [text, delta])
...
stream: "lifecycle"  (phase: endedAt)


No `stream: "thinking"` event observed across the entire response.

### Chat events (all delta + final)


{
  "event": "chat",
  "state": "delta",
  "hasText": true,
  "hasTextDelta": false,
  "hasThinking": false,
  "hasThinkingDelta": false
}

{
  "event": "chat",
  "state": "final",
  "hasText": true,
  "hasTextDelta": false,
  "hasThinking": false,
  "hasThinkingDelta": false
}

### Evidence that thinking IS stored

After the response completes, `chat.history` returns the message with thinking content present. Historical messages in the WebChat UI display a "thinking" section. This proves the gateway receives thinking from the provider and persists it, but does not stream it in real-time via WebSocket events.
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Summary

When extended thinking is enabled (Think: high, Reasoning: stream, model reasoning: true), the gateway stores thinking content in the transcript (visible via chat.history) but does not emit stream: "thinking" agent events via WebSocket during streaming, making real-time thinking display impossible for WebChat frontends.

Steps to reproduce

  1. Configure a custom Anthropic provider with reasoning: true on the model definition
  2. Set session-level thinking via /thinking high and /reasoning stream
  3. Confirm session status shows Think: high · Reasoning: stream
  4. Send a message via WebChat (Control UI)
  5. Monitor WebSocket frames for agent events during the response

Expected behavior

During streaming, the gateway should emit agent events with stream: "thinking" containing thinking content chunks, in addition to stream: "assistant" for text content. The chat delta/final events should report hasThinking: true and/or hasThinkingDelta: true when thinking content is present.

Actual behavior

  • All agent events during streaming have stream: "assistant" only — no stream: "thinking" events are emitted
  • All chat events (both delta and final state) report hasThinking: false and hasThinkingDelta: false
  • After the run completes, calling chat.history returns the message with thinking content included
  • This confirms the gateway receives and stores thinking content but does not forward it via WebSocket during streaming

OpenClaw version

2026.3.13 (commit 61d171a)

Operating system

Linux 6.18.7-arch1-1 (x64), Node v24.14.0

Install method

npm global

Model

custom-anthropic/claude-opus-4-6

Provider / routing chain

openclaw -> custom-anthropic (gateway.lazycat.ai, api: anthropic-messages) -> anthropic

Additional provider/model setup details

{
  "models": {
    "mode": "merge",
    "providers": {
      "custom-anthropic": {
        "baseUrl": "xxxx",
        "api": "anthropic-messages",
        "models": [
          {
            "id": "claude-opus-4-6",
            "name": "claude-opus-4-6 (Custom Provider)",
            "reasoning": true
          }
        ]
      }
    }
  }
}

Session-level: /thinking high and /reasoning stream both enabled. Session status confirms Think: high · Reasoning: stream.

Logs, screenshots, and evidence

### WebSocket agent events (excerpt — all stream values during a full response)


stream: "lifecycle"  (phase: startedAt)
stream: "assistant"  (dataKeys: [text, delta])  ← repeated for all content chunks
stream: "assistant"  (dataKeys: [text, delta])
stream: "assistant"  (dataKeys: [text, delta])
...
stream: "lifecycle"  (phase: endedAt)


No `stream: "thinking"` event observed across the entire response.

### Chat events (all delta + final)


{
  "event": "chat",
  "state": "delta",
  "hasText": true,
  "hasTextDelta": false,
  "hasThinking": false,
  "hasThinkingDelta": false
}

{
  "event": "chat",
  "state": "final",
  "hasText": true,
  "hasTextDelta": false,
  "hasThinking": false,
  "hasThinkingDelta": false
}

### Evidence that thinking IS stored

After the response completes, `chat.history` returns the message with thinking content present. Historical messages in the WebChat UI display a "thinking" section. This proves the gateway receives thinking from the provider and persists it, but does not stream it in real-time via WebSocket events.

Impact and severity

  • Affected: All WebChat / Control UI users who want to display real-time thinking during streaming
  • Severity: Medium — does not block core functionality, but prevents a key UX feature (real-time thinking display)
  • Frequency: 100% reproducible — observed across multiple messages with thinking enabled
  • Consequence: Custom WebChat frontends cannot implement real-time "thinking process" display; thinking content is only accessible after the full response completes via chat.history, defeating the purpose of streaming thinking

Additional information

  • The Reasoning: stream session setting implies thinking should be streamed, but the WebSocket events do not reflect this
  • The reasoning: true model flag was initially false (auto-defaulted); after manually setting it to true and restarting, thinking content began appearing in chat.history but still not in real-time WebSocket events
  • No stream: "thinking" agent event type was observed in any test run

extent analysis

Fix Plan

To resolve the issue of missing stream: "thinking" agent events during streaming, we need to modify the WebSocket event handling logic. The following steps outline the solution:

  • Update the agentEventEmitter function to include thinking content when reasoning is enabled and stream is set to "thinking".
  • Modify the chatEventGenerator function to correctly set hasThinking and hasThinkingDelta flags based on the presence of thinking content.

Code Changes

// Update agentEventEmitter function
function agentEventEmitter(eventData) {
  if (eventData.reasoning && eventData.stream === 'thinking') {
    // Emit stream: "thinking" event with thinking content
    ws.emit('agent', { stream: 'thinking', data: eventData.thinkingContent });
  }
  // ... existing code for emitting stream: "assistant" events
}

// Update chatEventGenerator function
function chatEventGenerator(eventData) {
  const hasThinking = eventData.thinkingContent !== null && eventData.thinkingContent !== undefined;
  const hasThinkingDelta = eventData.thinkingContentDelta !== null && eventData.thinkingContentDelta !== undefined;
  // ... existing code for generating chat events
  return {
    event: 'chat',
    state: 'delta', // or 'final'
    hasText: true,
    hasTextDelta: false,
    hasThinking: hasThinking,
    hasThinkingDelta: hasThinkingDelta
  };
}

Verification

To verify the fix, follow these steps:

  1. Apply the code changes and restart the server.
  2. Enable reasoning and set stream to "thinking" for a session.
  3. Send a message via WebChat and monitor WebSocket frames for agent events.
  4. Verify that stream: "thinking" events are emitted during streaming, containing thinking content chunks.
  5. Check that chat events (both delta and final state) report hasThinking: true and/or hasThinkingDelta: true when thinking content is present.

Extra Tips

  • Ensure that the reasoning flag is correctly set to true for the model and that the stream setting is set to "thinking" for the session.
  • Verify that the WebSocket connection is stable and that events are being emitted correctly.
  • Test the fix with different scenarios, such as multiple messages with thinking content, to ensure that the issue is fully resolved.

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…

FAQ

Expected behavior

During streaming, the gateway should emit agent events with stream: "thinking" containing thinking content chunks, in addition to stream: "assistant" for text content. The chat delta/final events should report hasThinking: true and/or hasThinkingDelta: true when thinking content is present.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING