Skip to content

feat(chat): show the estimated cost of each assistant reply in the message footer - #1697

Open
zenpasdan1-ai wants to merge 5 commits into
openclaw:mainfrom
zenpasdan1-ai:feat/message-cost-footer
Open

zenpasdan1-ai wants to merge 5 commits into
openclaw:mainfrom
zenpasdan1-ai:feat/message-cost-footer

Conversation

@zenpasdan1-ai

@zenpasdan1-ai zenpasdan1-ai commented Oct 10, 2026 •

Copy link
Copy Markdown

Builds on #551 (Show chat usage in assistant timestamp footer).
Related: #1433 (Chat context footer accumulates overlapping request totals): cost is per message, never summed and never reconciled against sessions.list; pinned by ChatMessageReceived_CostStaysOnItsOwnAssistantMessage.
Related: #1473 (fix(chat): correct context footer usage snapshots): touches the same files; this PR adds one new method and leaves SnapshotAssistantUsageContributionLocked unmodified.
Footer placement precedent: #1220 (Show response duration in the assistant-message model/speaker footer, closed not-planned).
Compatibility: does not call the usage.cost RPC (closed #1345); reads the cost field already present on assistant frames and history rows.

What Problem This Solves

The Desktop chat shows tokens and context usage under each assistant reply but not what the reply cost, so operators have to open the gateway Control UI or the /usage command to see the per-message cost the gateway already computes.

User Impact

User impact: each assistant message footer now ends with the gateway-reported cost of that reply, for example Assistant · 11:10 · qwen3.8-27b · 70.5K/131.1K (53%) · $0.588, when the gateway includes usage.cost.total on the message. Nothing changes when the gateway reports no cost.

The amount is the gateway's estimate from its configured per-token prices, not an invoice: for a local model it is a counter at whatever prices were configured, and subscription or OAuth providers may show a value that is never billed. No marker is added to the number; this matches the gateway Control UI, which renders the bare $ value.

Why This Change Was Made

The gateway attaches usage.cost.total to assistant message frames (observed live on the pre-rebase worktree) and to chat.history rows (observed on this head, see Real Behavior Proof). This PR reads that field into ChatMessageInfo.CostUsd, carries it on ChatEntryMetadata, and renders it through ChatUsageFormatter.FormatCost with the gateway Control UI precision (four decimals below $0.01, three below $1, otherwise two; amounts that would round to zero at four decimals (below $0.00005) render as <$0.0001; missing, zero, negative, or non-finite values are hidden). The footer itself keeps the #551 placement rule: it renders on the last bubble of each assistant run and only while tool calls are visible (Settings > Show tool calls).

The cost is attached to the latest assistant entry through a new self-contained ChatConversationState.SnapshotAssistantCost method instead of extending the usage-contribution path, so the usage snapshot code that #1473 reworks is left byte-for-byte unchanged. If #1473 lands first, the only expected touch is hunk ordering in OpenClawChatDataProvider (its hasUsage block is deleted; the SnapshotAssistantCost call stays); no ChatConversationState or ChatEntryMetadata conflict is expected because CostUsd sits after ContextPercent in the record and every positional construction stops at ContextPercent.

Evidence

  • Unit tests cover parsing (ParseChatHistoryPayload_AssistantRow_ReadsUsageCost and ParseChatHistoryPayload_AssistantRow_RejectsInvalidUsageCost through the real chat.history parser, three wire-level ChatEvent_*Cost* tests plus ProcessRawMessage_LegacyAssistantMessage_ReadsPayloadUsageCost through ProcessRawMessage), formatting (FormatCost_MatchesControlUiPrecision, FormatCost_ShowsFloorForCostBelowDisplayPrecision, FormatCost_HidesMissingZeroOrInvalidCost), the footer contract (ChatCostFooterContractTests), and the provider/state behavior (ten OpenClawChatDataProviderTests cases: merge onto a streaming entry, cost-only final, duplicate final with a snapshot-count baseline, zero cost on a fresh entry stays unset, cost stays on its own message, cost after a tool call, later cost replaces earlier cost with the identified-replay row pinned as dropped, sessions.updated preserves cost, history captures cost, history row without cost replaces the live cost).
  • Live proof on the previous head of this branch (before the rebase onto main and the footer wording change): the footer showed the gateway-reported cost next to time, model, and usage against a local Gateway 2026.9.9 with a local model whose prices were configured per million tokens, so the value behaved as a counter and updated per reply. Those screenshots show the earlier ~$x (virtual) wording and are not attached; the current-head capture is in Real Behavior Proof.

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 (parsing only: reads usage.cost.total from existing frames and history rows; no new RPC)
  • Setup or onboarding
  • Permissions, privacy, or security
  • Tests, CI, or docs

Required proof pools

  • windows-winui-interactive: the assistant message footer changed.

Validation

Run on head b00a02b (Windows 11 Pro build 26300, .NET SDK 10.0.401), 2026-10-10, from a clean working tree. Environment: $env:OPENCLAW_REPO_ROOT=<repo>; $env:OPENCLAW_TRAY_DATA_DIR=<isolated scratch directory outside the repo>. Full logs were kept outside the repo (validate-build.log, validate-shared.log, validate-tray.log, validate-cost-shared.log, validate-cost-tray.log).

  • .\build.ps1: exit 0. Proof-pool validation passed: 7 named pools checked., Documentation validation passed: 59 Markdown files checked., Build Summary: Shared, Cli, WinNodeCli, SetupEngine, WinUI all built (Debug, win-x64), All builds succeeded!.
  • dotnet test .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csproj (first run in this bin, so with restore): exit 1; total 4308, passed 4271, skipped 36, failed 1. The one failure is OpenClaw.Shared.Tests.TokenSanitizerTests.SanitizeLogMessage_RedactsCurrentUserAndMachineNames (Assert.Contains expected <host> in user=<user> machine=<user>, TokenSanitizerTests.cs line 283). It is environmental on the validation host, where USERNAME equals COMPUTERNAME (case-insensitively), so the machine name is redacted as <user> before the <host> rule applies; the same test fails identically on unmodified main on this host, no file touched by this PR is involved, and it is reported here as a failure rather than hidden. The 36 skips are the pre-existing integration tests that skip without their external prerequisites.
  • dotnet test .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csproj (with restore): exit 0; total 4023, passed 4023, skipped 0, failed 0.
  • Focused, dotnet test .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csproj --filter "FullyQualifiedName~Cost" --logger "console;verbosity=normal": exit 0; 128 passed, 0 failed, 0 skipped. Added by this PR (11 cases): OpenClawGatewayClientTests.ChatEvent_ReadsAssistantMessageUsageCost, ChatEvent_PrefersMessageUsageCostOverPayloadCost, ChatEvent_FallsBackToPayloadUsageCost_WhenMessageHasNone, ProcessRawMessage_LegacyAssistantMessage_ReadsPayloadUsageCost, ParseChatHistoryPayload_AssistantRow_ReadsUsageCost, ParseChatHistoryPayload_AssistantRow_RejectsInvalidUsageCost (6 rows). The other 117 matches are pre-existing tests the filter also selects: GatewayUsageInfoTests (3), OpenClawGatewayClientTests.HandleRequestError_UnknownMethod_UsageCost_SetsUnsupportedFlag, OpenClawGatewayClientTests.ParseUsageCostPayload_UpdatesLegacyUsageTotals, and 112 data rows of ExecApprovalSecretRedactorTests.RedactMatchesMacOsToolsModeVectors whose row text contains "cost".
  • Focused, dotnet test .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csproj --filter "FullyQualifiedName~Cost" --logger "console;verbosity=normal": exit 0; 37 passed, 0 failed, 0 skipped. Added by this PR (27 cases): ChatCostFooterContractTests.AssistantFooter_RendersCostThroughSharedFormatter; ChatUsageFormatterTests.FormatCost_MatchesControlUiPrecision (8 rows), FormatCost_HidesMissingZeroOrInvalidCost (5 rows), FormatCost_ShowsFloorForCostBelowDisplayPrecision; OpenClawChatDataProviderTests.ChatMessageReceived_AssistantFinal_MergesCostOntoStreamingEntry, ChatMessageReceived_CostOnlyFinal_AttachesCostToLatestAssistantEntry, ChatMessageReceived_DuplicateAssistantFinalWithCost_KeepsSingleCostAndUsage, ChatMessageReceived_ZeroCostOnFreshEntry_LeavesCostUnset, ChatMessageReceived_CostStaysOnItsOwnAssistantMessage, ChatMessageReceived_CostAfterToolCall_LandsOnFinalAssistantEntry, ChatMessageReceived_LaterAssistantFinalCost_ReplacesEarlierCost (3 rows), SessionsUpdated_PreservesAssistantCost, LoadHistoryAsync_CapturesAssistantCost, LoadHistoryAsync_HistoryRowWithoutCost_ReplacesLiveCost. The other 10 matches are pre-existing: Services.TrayDashboardSummaryBuilderTests (3) and UsageCostApplicationPolicyTests (7 incl. rows).
  • Branch: b00a02b9 fix(chat): address review findings for cost footer on top of 04e7c225 feat(chat): show the estimated cost of each assistant reply in the message footer, based on 037c17dc (fix(chat): make Enter send from the multiline composer #1674). main has since advanced by one commit (16299381, fix: preserve node containment settings when opening Sandbox #1683) that touches none of these files; git merge-tree --write-tree origin/main HEAD reports a clean merge. The validation above was not rerun on the merge result.

Real Behavior Proof

  • Environment tested: Windows 11 Pro (build 26300), OpenClaw Gateway 2026.9.9 (WSL), local OpenAI-compatible model with per-million-token prices configured in the gateway so usage.cost.total is reported; Release build of this head (app-identity release, product version 2026.9.9-feat-message-cost-footer) copied over the installed Desktop app (real tray data, same gateway pairing).

  • PR head or commit tested: b00a02b.

  • Exact steps or command run: close the Desktop, install the Release output of this head, start the app (new process), open a session whose assistant reply was produced before this process started, read the footer. That reply can only have come from chat.history.

  • Evidence after fix: footer under a stored assistant reply reads Assistant · 12:32 · qwen3.8-27b · 24.1K/131.1K (18%) · $0.256 (gateway store value 0.2561 for that message), rendered from chat.history in a freshly started app.

    Assistant footer ending with the per-message cost $0.256

  • Observed result: history rows on Gateway 2026.9.9 carry usage.cost; the cost is restored from history on a cold start, and the three-decimal precision branch rendered as specified. Context usage segment unchanged.

  • Screenshot or artifact links verified? Yes (the image above resolves; it is hosted on a branch of the PR author's fork).

  • Not verified or blocked:

    • Live final frame on this head: not captured. During the capture window the gateway-to-model transport hung after a model server restart (gateway logged transient same-model retry ... reason=timeout while the model server reported the request complete), so no fresh assistant final was observed on this head; the live path (ChatEvent_ReadsAssistantMessageUsageCost, ChatMessageReceived_AssistantFinal_MergesCostOntoStreamingEntry) is covered by unit tests only on this head. A live capture was observed on the pre-rebase worktree with identical parsing code and the earlier wording.
    • Accessibility pool command not yet run: .\scripts\run-proof-tests.ps1 -Project 'tests\OpenClaw.Tray.UITests\OpenClaw.Tray.UITests.csproj' -Filter 'Category=Accessibility' -ResultName 'winui-accessibility' -RuntimeIdentifier win-x64.
    • The sub-$0.01 and $1+ precision branches and the <$0.0001 floor are covered only by unit tests; no live provider on the test machine produces them.
    • Cloud or subscription providers (provider-billed cost, usage.cost.totalOrigin) were not exercised live.
    • Payload-only cost frames (fallback order message then payload) were not observed live; covered by the wire-level test only.
    • A gateway sending usage.cost as a bare number is intentionally ignored (pinned by a test row).
    • Localization: the footer cost string contains no words, so no resw change; if maintainers want an "estimate" marker it is a follow-up resw key composed in FooterText.
    • Follow-up (not in this PR): request models.list with includeDetails: true and surface the gateway local flag to annotate local-model pricing, and honor usage.cost.totalOrigin == "provider-billed".

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: N/A

Compatibility and Migration

  • Backward compatible? (Yes)
  • Config or environment changes? (No)
  • Migration needed? (No)
  • If yes, list the exact upgrade steps: N/A. ChatEntryMetadata is not JSON-serialized, so there is no persisted format change; ChatMessageInfo.CostUsd is a nullable addition and older gateways that omit the field produce the previous footer.

Rubber-duck review

Rubber-duck review was run on the pre-publication plan and again on the branch; findings applied: removed the hard-coded local-provider list (it can never be complete), adopted the Control UI precision instead of fixed F4, moved cost onto a dedicated SnapshotAssistantCost path so SnapshotAssistantUsageContributionLocked stays untouched for #1473, added the history-parser, legacy-payload, zero-cost, and duplicate snapshot-count tests, and corrected the floor and footer-gating wording in the docs. Decisions kept:

  • No marker: the Control UI renders the bare $ value and SessionInfo.Provider is operator-typed, so a hard-coded local-provider list can never be complete and would ship private provider ids. The "counter, not a bill" message lives in docs/CHAT_VISUAL_DESIGN.md and in this PR body.
  • Precision: 4 / 3 / 2 decimals by magnitude, mirroring formatCost in ui/src/lib/format.ts of openclaw/openclaw (commit 0acc55cfa8a973f9d1764f7641f41e5a38e88abe); two deliberate divergences: zero is hidden instead of $0.00, and values below $0.00005 render as <$0.0001. The three existing $ + F2 sites in the tray are totals where two decimals are right, so no shared helper was introduced.
  • Footer gating is unchanged from Show chat usage in assistant timestamp footer #551: the whole metadata footer (time, model, usage, cost) renders on the last bubble of each assistant run and only while tool calls are visible; widening that for cost alone is a separate decision.
  • Latest rendered frame wins: SnapshotAssistantCost overwrites a differing value, ignores an identical one, skips a reported zero on an entry that has no cost (renders the same as none), and never runs for identified duplicates because the queue classifier drops them first (pinned by the "m1" row of ChatMessageReceived_LaterAssistantFinalCost_ReplacesEarlierCost).
  • History wins on reload: an authoritative chat.history rebuild replaces live metadata for rows it covers, so a history row without usage.cost clears a live cost (pinned by LoadHistoryAsync_HistoryRowWithoutCost_ReplacesLiveCost).
  • Extraction order: message.usage.cost.total before payload.usage.cost.total on live frames; it is the proven live order and the same object chat.history reads. Token usage uses the reverse precedence; left as is to keep the diff small.
  • Multi-agent gateways: unaffected; [Bug]: usage.cost / commands.list / sessions.create fail with "session key 'main' has no explicit owner" on multi-agent gateways #1345 concerns the usage.cost RPC, which this PR does not call.
  • Telemetry: unaffected; display only, no new span attributes, metric tags, or exported fields (see docs/TELEMETRY.md).

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.

🤖 Generated with Claude Code

zenpasdan1-ai and others added 2 commits October 10, 2026 00:46
…ssage footer

Read usage.cost.total from assistant message frames and chat.history rows
into ChatMessageInfo.CostUsd, carry it on ChatEntryMetadata, and render it
after the usage summary in the assistant footer with the gateway Control UI
precision. The value is attached to the latest assistant entry through a
dedicated ChatConversationState.SnapshotAssistantCost path so the usage
snapshot logic that openclaw#1473 reworks is left untouched. Cost is hidden when the
gateway reports none.

Related: openclaw#1433, openclaw#1473, openclaw#551

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pin the chat.history cost ingress through the real parser (replacing the
reflection-only ExtractChatCost test), add a legacy payload.text cost test,
skip the redundant snapshot when a fresh entry reports a zero cost, make the
duplicate-final test count publishes against an uncosted baseline, guard the
footer contract test anchors, cite the upstream Control UI formatCost source,
and correct the docs: the <$0.0001 floor applies below $0.00005 and the whole
assistant footer stays gated by the tool-call visibility setting from openclaw#551.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@clawsweeper

clawsweeper Bot commented Oct 10, 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 P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Oct 10, 2026
@clawsweeper

clawsweeper Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge.

What this changes

This PR displays Gateway-reported per-message cost in native assistant reply footers.

Example: An assistant history row reports usage.cost.total = 0.2561.

  • Before: The native footer shows time, model, and context usage.
  • After: The footer also shows $0.256.

Review scores

Measure Result What it means
Overall readiness 🦪 silver shellfish (2/6) The patch is focused and the prior defects are repaired, but supplied runtime evidence does not cover the current changed paths.
Proof confidence 🦪 silver shellfish (2/6) Real behavior proof is necessary before merge. See Before merge.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Product

Kind: Feature · Worth it: Yes · Fix scope: Complete
User problem: Operators must leave native chat to see the Gateway's estimated cost for an individual reply.
Reason: The feature exposes existing Gateway information without new configuration or network calls; the current area-owner discussion accepts the repaired implementation and identifies proof as the remaining gate.

Merge readiness

⛔ Blocked before merge - 1 item remains

Keep this PR open: it adds distinct functionality absent from current main, and the two previously reported replay defects are repaired.

Priority: P3
Reviewed head: b91055a30c89e89556412987d3906cad45ec9818

Before merge

  • Add real behavior proof - The inspected b00a02b Windows screenshot shows $0.256 restored through chat.history in the native footer, but does not exercise b91055a's multipart carrier selection or live SnapshotAssistantCost path. Supply current-head screenshots or a recording showing a newly completed reply receiving its own cost and preserving that cost once after text/tool/text and text/media reload, plus the declared accessibility result; redact IPs, API keys, phone numbers, and non-public endpoints. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Findings

None.

Tests

  • Missing end-to-end proof: Current-head live-final and multipart reload rendering, including text-to-media, remain unshown; regression tests were inspected but not executed in this read-only review.
Agent review details

How this fits together

The shared Gateway client parses live events and history into typed messages; native chat state attaches their metadata to timeline entries, and the footer formatter produces the displayed cost.

flowchart LR
  A[Gateway live events] --> C[Shared message parser]
  B[Gateway chat history] --> C
  C --> D[Chat provider and history loader]
  D --> E[Conversation entry metadata]
  E --> F[Cost formatter]
  F --> G[Native assistant footer]
Loading

Technical review

Best possible solution:

Retain Gateway-owned per-message cost and render it once on the final assistant entry through the existing native footer.

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

This is a feature request; source inspection confirms current main lacks per-message cost display, and supplied older-head media demonstrates the proposed single-reply presentation.

Is this the best way to solve the issue?

The existing parser, conversation metadata, history loader, and footer formatter are appropriate owners; the change avoids a new RPC or competing usage accumulator.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against 16299381a4df.

Provenance checked

Testing

Proof path: shipped entry point.

Security

None.

Evidence

What I checked:

  • Introduced change: The pinned introduction diff adds cost parsing, entry metadata, live attachment, history carrier selection, and footer formatting; unrelated base-only changes are excluded. (b91055a30c89)
  • Current main lacks the feature: Current-main ChatUsageFormatter has no cost formatter, and its assistant footer joins time, model, and usage without cost. (src/OpenClaw.Tray.WinUI/Chat/ReactorChatTimeline.cs:1122, 16299381a4df)
  • Prior findings repaired: History carrier selection advances to the final text or media replay part. Provider regressions assert one priced entry for text/tool/text and text/media rows, with the media case priced on the final assistant entry. (src/OpenClaw.Tray.WinUI/Chat/ChatHistoryLoader.cs:524, b91055a30c89)
  • Inspected supplied proof: The linked b00a02b screenshot visibly shows $0.256 in a native stored-reply footer. The full body and latest author comment explicitly leave current-head live-final, multipart reload, and accessibility proof unfinished. The body was retrieved beyond the supplied excerpts; its captured source identity is c039dec0570bfa011b4252585490653038358f95ad9dcbd053a2d12ae0609566. (b00a02b987fd)
  • Recorded area-owner review: karkarl's current-head discussion accepts the replay repairs and identifies behavioral proof as the remaining gate: feat(chat): show the estimated cost of each assistant reply in the message footer #1697 (comment). (b91055a30c89)
  • Validation attribution: The author reports a passing current-head build and 4,024 passing Tray tests, with Shared results of 4,271 passed, 36 skipped, and one failure. The unchanged sanitizer replaces the username before the machine name, explaining the reported baseline failure when those names match. GitHub exposes only a successful dispatch check, not canonical build/test results. No build or test was run during this read-only review. (src/OpenClaw.Shared/TokenSanitizer.cs:585, b91055a30c89)

Likely related people:

  • the99missedcalls: Raw commit ff38d84 adds src/OpenClaw.Tray.WinUI/Chat/ChatUsageFormatter.cs:9 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
Change distribution Production +128/-14; tests +709/-0; docs +16/-2 Most growth covers parsing, live reconciliation, formatting, and multipart history regressions rather than new production infrastructure.

Labels

Label changes:

No label changes.

Label justifications:

  • P3: This is optional native-chat cost visibility with limited blast radius and no demonstrated core workflow failure.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence.

Rank-up moves

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

  • Provide current-head live-final, multipart reload, and accessibility 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-10T18:56:56.133Z sha b00a02b :: needs real behavior proof before merge. :: none
  • reviewed 2026-10-10T19:03:49.532Z sha b00a02b :: needs real behavior proof before merge. :: none
  • reviewed 2026-10-10T19:47:52.976Z sha b00a02b :: needs real behavior proof before merge. :: none
  • reviewed 2026-10-11T13:29:52.063Z sha bd205a9 :: needs real behavior proof before merge. :: [P2] Place history cost on the visible footer when media follows text

Reviewed October 12, 2026, 9:25 AM ET / 13:25 UTC (Revision 5).

@zenpasdan1-ai
zenpasdan1-ai marked this pull request as ready for review October 10, 2026 19:42
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-10T19:49:03.209482Z b00a02b Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

The test pinned method ordering and formatter fragments and would still pass if the cost were excluded from the rendered footer. The formatter and provider tests cover the behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b00a02b987

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/OpenClaw.Tray.WinUI/Chat/ChatHistoryLoader.cs Outdated
A chat.history assistant row with interleaved text and tool parts replays as several timeline entries. Its single usage cost was copied onto every one of them, so one charge rendered at each assistant run end. Attach it to the row's last text part only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@karkarl

karkarl commented Oct 11, 2026

Copy link
Copy Markdown
Collaborator

Global triage: HOLD_FOR_AUTHOR. Take confidence 45%; recommendation confidence 99%; effort medium; risk medium.

Reviewed exact head b00a02b987fd. Both independent reviewers confirmed one MEDIUM correctness defect, matching the unresolved inline review signal: ChatHistoryLoader copies one message-level CostUsd onto every replay part. For a historical text -> tool -> text message, the timeline can render the same charge on multiple assistant run-ending footers after reload. The live path attaches it once, so live and restored transcripts disagree.

The current screenshot proves cold-start history rendering, but not a newly completed live reply. Accessibility proof is unrun, full Shared validation has one reported baseline-dependent failure, and exact-head checks are dispatch-only with one cancelled job. This PR also overlaps #1473 in the history/metadata path and must be refreshed after that dependency is resolved.

Author action: assign the message cost to exactly one visible assistant replay entry, add a provider-level text/tool/text history regression that asserts a single cost before and after reload, and resolve the existing inline thread. Then collect current-head windows-winui-interactive live-final, reload, and accessibility proof plus canonical CI.

This is a triage classification, not a merge action. No branch changes, fixes, pushes, labels, CI reruns, or other remote mutations were made.

@zenpasdan1-ai

Copy link
Copy Markdown
Author

Pushed bd205a9 on top of the reviewed head:

  • History cost shown once. A chat.history row that replays as several entries (text, tool, text) now carries its cost on one entry only, the row's last text part. Regression test: LoadHistoryAsync_SplitAssistantRow_ShowsCostOnceOnLastTextPart.
  • Removed ChatCostFooterContractTests (source-text test that would pass even if the cost were dropped from the footer), as the review suggested.

Validation on this head: ./build.ps1 exit 0 (Debug and Release); Tray tests 4023 passed, 0 failed; Shared tests 4271 passed, 36 skipped, 1 failed (the same TokenSanitizerTests.SanitizeLogMessage_RedactsCurrentUserAndMachineNames failure as before, caused by USERNAME equal to COMPUTERNAME on the validation host; the Shared run was on the commit before a test-only amend of the Tray test file).

Still open on my side: a live completion-to-footer capture on the current head and the accessibility proof pool. I will rebase after #1473 lands.

🤖 Generated with Claude Code

@clawsweeper clawsweeper Bot added 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. labels Oct 11, 2026
@karkarl

karkarl commented Oct 12, 2026

Copy link
Copy Markdown
Collaborator

Global triage: HOLD_FOR_AUTHOR. Take confidence 52%; recommendation confidence 99%; effort medium; risk medium.

Reviewed exact head bd205a992f4a, including the two-commit delta from previously reviewed b00a02b987fd. The delta fixes the duplicate-cost replay finding for text -> tool -> text history rows, but it introduces a remaining P2 display defect: the carrier selection prefers a non-empty text part over a later media part. Because ReactorChatTimeline renders footer metadata only on the run's final assistant entry, a text -> image history row leaves the cost on the earlier text entry and hides it after reload. The current ClawSweeper review independently reports the same reachable case at ChatHistoryLoader.cs:529-531.

This exact head also has only dispatch/security checks, not canonical build and test CI. The body validation and screenshot are for b00a02b9, not this head, and the declared windows-winui-interactive live-final, multipart reload, and accessibility proof remain unverified.

Author action: attach the row cost to the final rendered assistant replay entry, including media, and add a provider-level text -> media regression asserting one visible cost. Then run exact-head required validation and collect current-head live-final, multipart reload, and accessibility proof before requesting review.

This is a triage classification, not a merge action. No branch changes, fixes, pushes, labels, CI reruns, or other remote mutations were made.

The cost carrier preferred a text part over a later media part. The footer renders on the run's final assistant entry, so a text then image row kept the cost on the earlier text entry and hid it after reload. Attach it to the last part that renders an assistant entry, text or media.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zenpasdan1-ai

Copy link
Copy Markdown
Author

Pushed b91055a for the text then media case from the triage note.

  • The history row's cost now goes to the last replay part that renders an assistant entry (text or media), not the last text part, so it lands where the footer renders.
  • Regression test: LoadHistoryAsync_TextThenMediaRow_ShowsCostOnceOnFinalMediaEntry (one priced entry, and it is the final assistant entry). LoadHistoryAsync_SplitAssistantRow_ShowsCostOnceOnLastTextPart still passes.

Exact-head validation on b91055a: ./build.ps1 exit 0; Tray tests 4024 passed, 0 failed; Shared tests 4271 passed, 36 skipped, 1 failed (TokenSanitizerTests.SanitizeLogMessage_RedactsCurrentUserAndMachineNames, host-specific: USERNAME equals COMPUTERNAME on the validation machine, same on unmodified main).

Not done yet: current-head live-final capture, multipart reload capture, and the accessibility proof pool. The screenshot in the body is still from b00a02b.

🤖 Generated with Claude Code

@karkarl

karkarl commented Oct 12, 2026

Copy link
Copy Markdown
Collaborator

Global triage: NEEDS_HUMAN_TEST. Take confidence 78%; recommendation confidence 99%; effort medium; risk medium.

Reviewed exact head b91055a30c89, including the one-commit delta from bd205a992f4a. The delta repairs the prior text-then-media replay defect: carrier selection now advances to the last replay part that renders an assistant entry, and LoadHistoryAsync_TextThenMediaRow_ShowsCostOnceOnFinalMediaEntry verifies that the row has one priced entry and that it is the final assistant entry. The existing split text/tool/text regression remains in place.

Author-reported exact-head local validation has the build and all 4,024 Tray tests passing. Shared tests report 4,271 passed, 36 skipped, and one host-specific TokenSanitizerTests.SanitizeLogMessage_RedactsCurrentUserAndMachineNames failure that also reproduces on unmodified main when USERNAME == COMPUTERNAME. GitHub currently exposes only the successful dispatch check for this head, not canonical build/test CI.

The remaining gate is current-head behavioral proof. Collect windows-winui-interactive evidence for live-final cost rendering, multipart reload including text-to-media, and accessibility. Replace the stale screenshot from b00a02b9, then request final exact-head review.

This is a triage classification, not a merge action. No branch changes, fixes, pushes, labels, CI reruns, or other remote mutations were made.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: usage.cost / commands.list / sessions.create fail with "session key 'main' has no explicit owner" on multi-agent gateways

2 participants