Skip to content

feat(chat): show tokens per second and context usage below the composer - #1748

Merged
joelagnel merged 5 commits into
openclaw:mainfrom
larroy:feat/chat-throughput-indicator
Oct 29, 2026
Merged

joelagnel merged 5 commits into
openclaw:mainfrom
larroy:feat/chat-throughput-indicator

Conversation

@larroy

@larroy larroy commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

What Problem This Solves

The native chat gives no sense of how fast the model is responding or how full the context window is while you work.

User Impact

User impact: a slim strip below the composer, in both the tray chat window and the Hub chat page, shows tokens per second for the latest model response, with the mean (μ) and p95 over the last 50 measured model calls in that session. Next to it is a context-window bar with used/total tokens and a percentage (for example 45.4K/200K (23%)).

  • While the model streams, the current value is a live estimate marked ~.
  • Before a session has any measurement, the tps values show —.
  • The bar is hidden until the context window size is known.
  • The numbers are kept in memory only and reset when the app restarts.

Why This Change Was Made

The Gateway does not report tokens per second, so the app works it out from event timing.

  • Each Gateway usage agent event gives the run's total output tokens so far. The app takes the increase since the previous event as that model call's output, and divides it by the time from the call's first streamed text to that event. On a Gateway that sends no usage events, it falls back to the token count on the final assistant message. Each model call is counted once.
  • A run must have an observed start, either direct or opened from the reset buffer, before its totals count. For a run whose start was missed (for example, the app connected mid-run), the first total only sets the baseline, so it never turns into one huge outlier. Lifecycle end or error closes any open window, so an aborted run cannot leave one behind.
  • Only these exact measurements feed μ and p95. The live ~ value is a rough estimate of about 4 characters per token.
  • Live Gateway 2026.9.9 logs showed reasoning arriving as stream=thinking deltas while the reply text arrives in a single burst. So the measurement uses the thinking and usage streams, which the chat timeline otherwise ignores.
  • The strip listens for throughput changes directly and reads the current session's stats each time it draws. A thinking update redraws only the strip, and switching sessions never shows the previous session's numbers.
  • Context usage is worked out once and shared by the existing usage pill and the new bar. The existing pill text is unchanged.

Evidence

  • ChatThroughputTrackerTests (13) cover:

    • per-call deltas from run-cumulative totals, with no double counting at the final message
    • a reset at each new run
    • tool activity restarting the timing window
    • replies too short to measure
    • the characters-per-token live estimate
    • a 50-sample window with nearest-rank p95
    • samples kept separate per session
    • change notifications
    • runs with a missed start adopting the baseline instead of recording the run total
    • run end closing usage windows while keeping the final-message fallback
  • ChatEventMapperThroughputTests check that thinking deltas count only the delta, that persistence receipts are ignored, and that usage totals are parsed.

  • A provider test replays the event order seen on the live Gateway (lifecycle start, thinking deltas, usage, reply in one burst, final) and asserts exactly 50 tok/s.

    • Before the stream fix, this order recorded nothing. That matches the reported bug where the strip always showed —.
  • A provider test with no observed run start records no outlier, and the next call in the same run still measures exactly 60 tok/s.

  • A provider test covers the reset-gate ordering: a prior run records 100 tokens over 2 seconds (50 tok/s), sessions.reset buffers the next lifecycle start until chat.send is accepted, and the new run's 150 tokens over 2 seconds record 75 tok/s rather than (150 - 100) / 2 = 25. The buffered start does not reset the baseline until it is accepted.

  • Rubber-duck review (reviewer agent) of the first commit found:

    • one P2: buffered or missed run starts left a stale baseline or an open window, which produced μ/p95 outliers
    • three P3s: a stale-session render race in the strip, tooltip wording that said "reply" where samples are per model call, and missing tests

    All four are fixed in the second commit. The review confirmed that every existing ChatUsageFormatter.Format overload gives byte-identical output.

  • ClawSweeper review of d9d8692 (needs changes, P2) asked for the same buffered-start reset, plus a provider test of the start-before-send-result ordering with a prior measurement. That open is initialized in HandleOpenedLifecycle, and the provider test above covers the requested ordering. The review was against a revision that did not include commit acaacff0.

  • ChatUsageFormatterTests gained tests for context resolution and the tps text format. All existing output tests pass unchanged.

Change Type

  • Bug fix
  • Feature
  • Refactor
  • Docs or instructions
  • Tests or validation
  • Security hardening
  • Chore or infrastructure

Scope

  • Tray or WinUI UX
  • Windows node capability
  • Local MCP or winnode
  • Gateway, connection, or pairing
  • Setup or onboarding
  • Permissions, privacy, or security
  • Tests, CI, or docs

Required proof pools

  • windows-winui-interactive: a new visible strip below the chat composer, with its own accessibility names and tooltips.

Validation

Run on the current head, rebased on origin/main (ARM64 Windows host):

  • ./run-app-local.ps1: WinUI built with 0 errors, and the app launched. -AllowNonMain was removed upstream in improve(dev): build only the tray graph in run-app-local.ps1 #1586 (improve(dev): build only the tray graph in run-app-local.ps1).
  • dotnet test ./tests/OpenClaw.Shared.Tests/OpenClaw.Shared.Tests.csproj --no-restore: 4313 passed, 36 skipped, 0 failed.
  • dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore: 4107 passed, 0 failed.

Follow-up closeout on this x64 host, after 4b0cfa27:

  • ./build.ps1: all projects succeeded.
  • dotnet test ./tests/OpenClaw.Shared.Tests/OpenClaw.Shared.Tests.csproj: 4350 passed, 36 skipped, 0 failed. --no-restore could not run because the shared test assets file was missing in this worktree, so restore ran first.
  • dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore: 4115 passed, 0 failed.
  • Focused: BufferedLifecycleStartAfterReset_ResetsThroughputBaseline passed.

Real Behavior Proof

  • Environment tested: Windows 11 ARM64, Gateway 2026.9.9 (live tray log)
  • PR head or commit tested: current head of this branch
  • Exact steps or command run: compared the live openclaw-tray.log event sequence of real chat turns with the Gateway source (emitAgentRunOutputTokens, stream: "thinking"). Then built and launched with ./run-app-local.ps1, enabled Local MCP, and confirmed with winnode --list-tools that app.chat.send and app.chat.snapshot are listed.
  • Evidence after fix: the provider tests replaying the observed live order record 50 tok/s and 60 tok/s. The buffered post-reset start records 75 tok/s instead of the contaminated 25 tok/s. The app builds and launches with no startup errors.
  • Observed result: on the first build, the tps fields stayed — on a live Gateway. The cause was the burst reply and the ignored thinking and usage streams, which this head fixes.
  • Screenshot or artifact links verified? N/A
  • Not verified or blocked: current-head visual proof of a live streaming turn (windows-winui-interactive). No Gateway was reachable for the retest: nothing was listening on 127.0.0.1:18789, the default profile's Gateway record has no credentials, and the Dev profile that ran the earlier turns no longer exists. Local MCP itself worked (app.connection.status reported LocalMcpOnly, Idle).

Security Impact

  • New permissions or capabilities? No
  • Secrets or tokens handling changed? No
  • New or changed network calls? No
  • Command or tool execution surface changed? No
  • Data access scope changed? No
  • If any answer is Yes, explain the risk and mitigation:

Compatibility and Migration

  • Backward compatible? Yes
  • Config or environment changes? No
  • Migration needed? No
  • If yes, list the exact upgrade steps:

Review Conversations

  • I replied to or resolved every bot review conversation addressed by this PR.
  • I left unresolved only conversations that still need maintainer judgment.

@clawsweeper

clawsweeper Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@clawsweeper clawsweeper Bot added clawsweeper:intake:feature Preliminary submission classification; full source review pending. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed clawsweeper:intake:feature Preliminary submission classification; full source review pending. labels Oct 16, 2026
@clawsweeper

clawsweeper Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex review: needs maintainer review before merge.

What this changes

This PR adds session-specific response-speed statistics and a context-usage bar below the native chat composer.

Example: A model call produces 100 output tokens over two observed seconds.

  • Before: Chat shows no response-speed measurement.
  • After: The composer strip shows 50.0 tps and incorporates the measurement into that session's mean and p95.

Review scores

Measure Result What it means
Overall readiness 🦐 gold shrimp (3/6) Useful, focused implementation with the earlier accounting defects addressed; historical visible evidence and provider regressions support limited confidence until current behavior is demonstrated.
Proof confidence 🦐 gold shrimp (3/6) Real behavior proof is not required for maintainer- or bot-authored pull requests.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Product

Kind: Feature · Worth it: Yes · Fix scope: Complete
User problem: Users cannot see model response speed or a persistent context-window bar beside the composer.
Reason: The feature provides useful feedback without adding settings or persistence, and its direction is supported by collaborator authorship and explicit reviewer approval.

Merge readiness

✅ Ready for maintainer review

Keep open: this collaborator-authored feature remains absent from main, has explicit collaborator approval, and has no actionable source-level findings.

Priority: P2
Reviewed head: c68e8509dea3e2f2164a5368c669ec5aee4cc2a1

Before merge

None.

Findings

None.

Tests

  • Missing end-to-end proof: Current-head Workspace rendering, live streaming, session switching, and mid-run reconnect behavior remain unverified through the shipped app; the author reports the reconnect regression failing before its repair.
Agent review details

How this fits together

Gateway lifecycle, text, thinking, and usage events enter the chat provider; an in-memory tracker calculates session statistics that a Reactor strip renders alongside existing context metadata.

flowchart LR
  G[Gateway events] --> P[Chat provider]
  P --> T[Throughput tracker]
  P --> M[Existing chat metadata]
  T --> S[Reactor statistics strip]
  M --> F[Usage formatter]
  F --> S
Loading

Technical review

Best possible solution:

Retain the focused in-memory tracker and Reactor strip while preserving existing context formatting and connection lifecycle ownership.

Do we have a high-confidence way to reproduce the issue?

This is a feature request rather than a current-main bug; source inspection confirms main lacks the response-speed strip.

Is this the best way to solve the issue?

The implementation is appropriately scoped: the tracker owns bounded per-session measurements, the strip owns rendering and subscription cleanup, and context resolution reuses the existing formatter without changing its output.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against 0a68951e794d.

Provenance checked

Testing

Proof path: in-process harness.

Security

None.

Evidence

What I checked:

  • Introduced change and main comparison: The pinned introduced diff adds the tracker and strip; current main retains the original formatter and composer composition without this feature. (src/OpenClaw.Tray.WinUI/Chat/OpenClawReactorChatRoot.cs:410, c68e8509dea3)
  • Earlier accounting findings addressed: Accepted buffered lifecycle starts initialize the tracker, and connection transitions invalidate open windows and cumulative baselines while retaining completed samples; provider regressions cover both reported failures. (src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs:1180, c68e8509dea3)
  • Recorded direction approval: joelagnel confirmed the earlier reconnect defect and subsequently wrote “LGTM, please merge after clawsweeper passes” at feat(chat): show tokens per second and context usage below the composer #1748 (comment).
  • Inspected visible evidence: The downloaded October 16 screenshot visibly shows 73.5 tps, mean 90.8, p95 115, and context 99.2K/262.1K (37%); the other three images belong to the retired-popup refactor and do not demonstrate this PR's throughput behavior.
  • Policy and validation: Read the complete root and WinUI AGENTS.md files and applied the simplification, test-audit, and proof guidance; no maintainer-notes directory exists, no helper or second reviewer ran, and no builds or tests were executed during this read-only review. (AGENTS.md, c68e8509dea3)
  • History inspection limits: Scoped history and blame established the usage formatter, Reactor migration, and runtime-owner refactor; deeper follow/pickaxe reads encountered unavailable historical blobs, and the previous reviewed SHA was unavailable locally. (0a68951e794d)

Likely related people:

  • Barbara Kudiess: Raw commit f8a8825 adds src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs:1037 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: f8a8825ccbb4; files: src/OpenClaw.Tray.WinUI/Chat/OpenClawChatDataProvider.cs)
  • the99missedcalls: Raw commit ff38d84 adds src/OpenClaw.Tray.WinUI/Chat/ChatUsageFormatter.cs:13 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: ff38d8499c48; files: src/OpenClaw.Tray.WinUI/Chat/ChatUsageFormatter.cs)

Review metrics

Metric Value Why it matters
Introduced source and test delta Production/resources +577/-25; tests/project +481/-3 The main additions are a 246-line statistics owner and 122-line renderer; the tests cover distinct accounting, parsing, formatting, and provider lifecycle boundaries.

Labels

Label changes:

  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.
  • remove rating: 🦪 silver shellfish: Current PR rating is rating: 🦐 gold shrimp, so this older rating label is no longer current.

Label justifications:

  • P2: This is a bounded chat visibility improvement with useful session metrics and no demonstrated urgent runtime regression.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR.

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Supply the outstanding current-head Workspace rendering and reconnect evidence.

Rating scale

6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

History

Review history (4 earlier review cycles)
  • reviewed 2026-10-16T19:39:11.471Z sha d9d8692 :: needs changes before merge. :: [P2] Reset throughput accounting when a buffered lifecycle start is accepted
  • reviewed 2026-10-16T23:31:00.181Z sha 4b0cfa2 :: needs changes before merge. :: [P2] Invalidate throughput accounting across connection changes
  • reviewed 2026-10-20T05:08:57.871Z sha 49752b7 :: needs changes before merge. :: [P2] Invalidate throughput accounting across connection changes
  • reviewed 2026-10-27T02:57:45.040Z sha 6b6f755 :: needs maintainer review before merge. :: none

Reviewed October 28, 2026, 7:48 PM ET / 23:48 UTC (Revision 5).

@plarroy-nv

Copy link
Copy Markdown
Contributor
Screenshot 2026-10-16 at 12 16 20 PM

@larroy
larroy requested review from bkudiess and karkarl and removed request for karkarl October 16, 2026 23:16
@larroy
larroy force-pushed the feat/chat-throughput-indicator branch from fdc37c9 to acaacff Compare October 16, 2026 23:17
@larroy

larroy commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the P2 from the review of d9d8692.

The accounting hole was real on that revision: StartRun ran only for a directly processed lifecycle start. After sessions.reset, the reset gate buffers that event until chat.send is accepted (or a matching user echo opens it), and those paths call HandleOpenedLifecycle without going through ObserveThroughput. A new run reporting 150 tokens over 2 seconds after a prior 100-token run would record (150 - 100) / 2 = 25 tps instead of 75.

That open now initializes the tracker in HandleOpenedLifecycle (acaacff0, already on the branch when the review posted; the review SHA did not include it). A usage total for a run whose start was missed only becomes the baseline, so it cannot become one outlier sample.

The missing coverage is in 4b0cfa27: BufferedLifecycleStartAfterReset_ResetsThroughputBaseline replays the start-before-send-result ordering with a prior measurement and asserts 75 tps, sample count 2. The buffered start does not reset the baseline until send acceptance opens it.

Closeout on this head:

  • ./build.ps1: succeeded
  • dotnet test ./tests/OpenClaw.Shared.Tests/OpenClaw.Shared.Tests.csproj: 4350 passed, 36 skipped, 0 failed
  • dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore: 4115 passed, 0 failed
  • focused regression: 1 passed

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added clawsweeper:intake:feature Preliminary submission classification; full source review pending. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. clawsweeper:intake:feature Preliminary submission classification; full source review pending. labels Oct 16, 2026
@larroy

larroy commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator Author

@joelagnel @karkarl please review.

@larroy
larroy requested review from joelagnel and karkarl October 20, 2026 04:25
@larroy
larroy force-pushed the feat/chat-throughput-indicator branch from 4b0cfa2 to 49752b7 Compare October 20, 2026 04:32
@larroy

larroy commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added clawsweeper:intake:feature Preliminary submission classification; full source review pending. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. clawsweeper:intake:feature Preliminary submission classification; full source review pending. labels Oct 20, 2026
@larroy

larroy commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator Author

@clawsweeper what's missing for waiting for maintainer look tag?

@clawsweeper

clawsweeper Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

@clawsweeper what's missing for waiting for maintainer look tag? is retired; ClawSweeper now only reviews.

@larroy larroy added status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Oct 20, 2026
@joelagnel

Copy link
Copy Markdown
Collaborator

On the current head (49752b775f8e769bc61adb9a635abb6086b4918c), I confirmed the reconnect scenario ClawSweeper also found remains unaddressed. Run A reports 100 cumulative output tokens; the connection drops before its terminal event, leaving the throughput tracker's baseline at 100. The app reconnects after run B has already started, so it misses B's start. After two seconds of B's observed text, a usage total of 5,000 arrives. The tracker records (5,000 - 100) / 2 = 2,450 tps as one sample, skewing mean and p95, even though that total includes tokens from before B's observed timing window. The earlier buffered sessions.reset fix does not cover this disconnect path.

@larroy
larroy force-pushed the feat/chat-throughput-indicator branch from 49752b7 to 83a4b99 Compare October 27, 2026 01:10
@larroy

larroy commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the reconnect P2 from ClawSweeper and @joelagnel in 6b6f7550.

The finding was real. OnStatusChanged advanced the connection generation but never told the throughput tracker, so a run's known baseline survived a disconnect. A post-reconnect usage total for a run whose start was missed was then subtracted from the pre-disconnect baseline: (5000 - 100) / 2 = 2450 tps.

Fix: ChatThroughputTracker.InvalidateRuns() runs on every disconnect and reconnect, in the same block that finishes telemetry turns. Each session's open timing window closes and its baseline becomes unknown, so the next usage total only sets the baseline. Completed samples are kept.

Tests:

  • ReconnectDuringRunWithMissedStart_DoesNotSubtractPreDisconnectBaseline replays the reported order: run A reports 100, disconnect before its end, reconnect mid-run B, 2 s of thinking, usage 5000. It failed before the fix (2 samples, the outlier recorded) and passes after: 1 sample (50 tps), then the next call measures 60 tps.
  • InvalidateRuns_KeepsSamplesAndAdoptsNextUsageAsBaseline covers the tracker directly.

Also rebased on main. f7a1e93d adapts the strip to #1688 (refactor(chat): remove the standalone tray chat popup): it drops the retired IsCompact prop and ChannelGroup.cs test include, and keeps the narrow context-bar breakpoint local to the strip.

Validation on this head (ARM64 Windows):

  • ./build.ps1: all projects succeeded.
  • dotnet test ./tests/OpenClaw.Shared.Tests/OpenClaw.Shared.Tests.csproj --no-restore: 4650 passed, 24 skipped, 0 failed.
  • dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore: 4584 passed, 4 failed. The 4 are BuildPrerequisiteTests.CheckOnly_UsesTheAppLocalRuntimeResolver, which set PROCESSOR_ARCHITECTURE=AMD64 while build.ps1 still detects this ARM64 host. Neither file is touched by this PR.
  • Not verified: a live mid-run reconnect against a real Gateway (none reachable).

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added clawsweeper:intake:feature Preliminary submission classification; full source review pending. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. clawsweeper:intake:feature Preliminary submission classification; full source review pending. labels Oct 27, 2026
@joelagnel

Copy link
Copy Markdown
Collaborator

LGTM, please merge after clawsweeper passes.

Add a slim strip under the native Reactor chat composer (tray ChatWindow and
Hub ChatPage) showing current tokens/sec with mean (μ) and p95 over the last
50 measured replies per session, plus a context-window bar with used/total.

- ChatThroughputTracker: per-thread, in-memory. Live value is a chars/4
  estimate over streamed thinking/assistant text. Exact samples are one model
  call's output tokens over its streaming window, closed by the gateway
  `usage` agent event (run-cumulative outputTokens, diffed per call); the final
  assistant message's OutputTokens is the fallback when no usage stream exists.
- ChatEventMapper reads `thinking` deltas and `usage` totals, which are not
  timeline events.
- The strip subscribes to provider ThroughputChanged so thinking/usage updates
  re-render only the strip, not the timeline.
- ChatUsageFormatter resolves context usage once for both the existing pill
  and the bar; existing Format outputs are unchanged.
…un starts

Address rubber-duck review of the throughput strip:
- Start a run for lifecycle starts opened from the reset buffer
  (HandleOpenedLifecycle), not only for directly processed start events.
- Track whether the run's cumulative token baseline is known. A usage total
  for a run whose start was missed (provider created mid-run, ended run) only
  becomes the baseline, instead of being recorded as one call's tokens.
- End runs on lifecycle end/error: close usage-run segments so aborted runs
  cannot leave a stale window open; keep the fallback segment for the final
  message that arrives after lifecycle end.
- Strip reads stats from the provider in Render with a render-token
  subscription, so a session switch never shows the previous session's tps.
- Tooltip: samples are per model call, not per reply.
- Tests for thinking receipts, usage parsing, missed starts, and EndRun.
ClawSweeper's review of d9d8692 asked for a provider test of the
start-before-send-result ordering with a prior measurement. After
sessions.reset, a lifecycle start buffered until chat.send is accepted
must record the new run's tokens, not the delta from the previous run.
main openclaw#1688 removed compact chat (IsCompact, ChatVisuals.CompactSessionBreakpoint, ChannelGroup.cs). Drop the strip's IsCompact prop, keep its narrow context-bar breakpoint local, and remove the stale ChannelGroup.cs test include.
A connection transition can drop lifecycle start/end events, so a pre-disconnect run baseline was subtracted from a post-reconnect run total ((5000 - 100) / 2 = 2450 tps). OnStatusChanged now calls ChatThroughputTracker.InvalidateRuns on disconnect/reconnect: open windows close and baselines become unknown; completed samples are kept.
@larroy
larroy force-pushed the feat/chat-throughput-indicator branch from 6b6f755 to c68e850 Compare October 28, 2026 21:29
@larroy

larroy commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

@clawsweeper review

@clawsweeper

clawsweeper Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added clawsweeper:intake:feature Preliminary submission classification; full source review pending. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. clawsweeper:intake:feature Preliminary submission classification; full source review pending. labels Oct 28, 2026
@joelagnel
joelagnel merged commit 1beeb01 into openclaw:main Oct 29, 2026
28 checks passed
larroy added a commit to larroy/openclaw-windows-node that referenced this pull request Oct 30, 2026
…er (openclaw#1748)

* feat(chat): show tokens/sec and context usage below the composer

Add a slim strip under the native Reactor chat composer (tray ChatWindow and
Hub ChatPage) showing current tokens/sec with mean (μ) and p95 over the last
50 measured replies per session, plus a context-window bar with used/total.

- ChatThroughputTracker: per-thread, in-memory. Live value is a chars/4
  estimate over streamed thinking/assistant text. Exact samples are one model
  call's output tokens over its streaming window, closed by the gateway
  `usage` agent event (run-cumulative outputTokens, diffed per call); the final
  assistant message's OutputTokens is the fallback when no usage stream exists.
- ChatEventMapper reads `thinking` deltas and `usage` totals, which are not
  timeline events.
- The strip subscribes to provider ThroughputChanged so thinking/usage updates
  re-render only the strip, not the timeline.
- ChatUsageFormatter resolves context usage once for both the existing pill
  and the bar; existing Format outputs are unchanged.

* fix(chat): keep throughput samples honest across missed or buffered run starts

Address rubber-duck review of the throughput strip:
- Start a run for lifecycle starts opened from the reset buffer
  (HandleOpenedLifecycle), not only for directly processed start events.
- Track whether the run's cumulative token baseline is known. A usage total
  for a run whose start was missed (provider created mid-run, ended run) only
  becomes the baseline, instead of being recorded as one call's tokens.
- End runs on lifecycle end/error: close usage-run segments so aborted runs
  cannot leave a stale window open; keep the fallback segment for the final
  message that arrives after lifecycle end.
- Strip reads stats from the provider in Render with a render-token
  subscription, so a session switch never shows the previous session's tps.
- Tooltip: samples are per model call, not per reply.
- Tests for thinking receipts, usage parsing, missed starts, and EndRun.

* test(chat): cover buffered post-reset throughput baseline reset

ClawSweeper's review of d9d8692 asked for a provider test of the
start-before-send-result ordering with a prior measurement. After
sessions.reset, a lifecycle start buffered until chat.send is accepted
must record the new run's tokens, not the delta from the previous run.

* fix(chat): align throughput strip with retired compact chat after rebase

main openclaw#1688 removed compact chat (IsCompact, ChatVisuals.CompactSessionBreakpoint, ChannelGroup.cs). Drop the strip's IsCompact prop, keep its narrow context-bar breakpoint local, and remove the stale ChannelGroup.cs test include.

* fix(chat): invalidate throughput baselines across reconnects

A connection transition can drop lifecycle start/end events, so a pre-disconnect run baseline was subtracted from a post-reconnect run total ((5000 - 100) / 2 = 2450 tps). OnStatusChanged now calls ChatThroughputTracker.InvalidateRuns on disconnect/reconnect: open windows close and baselines become unknown; completed samples are kept.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants