Skip to content

feat: align native macOS chat with the web chat capability set#109712

Merged
steipete merged 15 commits into
mainfrom
claude/macos-chat-web-ui-align-b2dd25
Jul 17, 2026
Merged

feat: align native macOS chat with the web chat capability set#109712
steipete merged 15 commits into
mainfrom
claude/macos-chat-web-ui-align-b2dd25

Conversation

@steipete

Copy link
Copy Markdown
Contributor

What Problem This Solves

The native macOS chat lags the web Control UI chat in day-to-day capabilities, even though much of the machinery already exists. Several fully implemented shared surfaces were unreachable on macOS: the sessions manager sheet (ChatSessionsSheet) was dead code with no trigger anywhere, assistant reasoning/tool traces were hard-disabled, talk mode / voice notes / per-message Listen were implemented in OpenClawChatUI and wired on iOS but never injected by the macOS host, and the mac transport silently dropped the verboseLevel session setting. The composer also lacked three everyday web-chat features: input history recall, reply/quote, and per-session draft retention.

Why This Change Was Made

Aligning the native macOS chat with the web chat's capability set, preferring host wiring of existing shared code over new surface area. Two staged commits:

1. feat(macos) — host wiring (mac app + minimal shared passthroughs)

  • Sessions manager reachable: Sessions… toolbar action + Shift-Cmd-S opens the Active/Archived manager (gateway search, rename, pin, archive, restore). The unreachable showSessions state in OpenClawChatView is deleted.
  • Assistant reasoning & tool activity visible in the full window, with a persisted toggle (openclaw.webchat.showAssistantTrace, default on; compact panel stays minimal).
  • New MacChatSurface observing wrapper bridges live state into the once-constructed NSHostingController hierarchy: talk control (bridged to the existing TalkModeController/AppStateStore paths without touching the menu-bar overlay), voice-note recording (blocked while Talk Mode owns mic capture), per-message Listen via gateway tts.speak bound to the transport's server lease with local synthesis fallback (mirrors the iOS client), and starter prompts on empty sessions.
  • MacGatewayChatTransport now forwards verboseLevel in sessions.patch instead of dropping it.

2. feat(clients) — shared composer parity (macOS + iOS)

  • Input history: Up/Down recall of prior inputs (session-scoped, cap 100, transcript-seeded plus locally sent slash commands, draft stash/restore, Escape cancels), mirroring ui/src/pages/chat/input-history.ts semantics. Slash-panel navigation keeps priority.
  • Reply/quote: context-menu Reply → cancellable composer chip → outgoing message prepends the exact web blockquote format from ui/src/pages/chat/chat-send.ts (prependReplyQuote, same Markdown escape set, 500/120 UTF-16 truncation limits), so transcripts look identical across surfaces.
  • Per-session drafts: composer text survives session switches (in-memory; revision-guarded so races with in-flight sends cannot eat newer text). Accepted tradeoffs vs web (no cross-launch persistence, no attachment drafts) are noted in code comments.

All shared-package API changes are additive with defaulted parameters; iOS call sites compile unchanged.

User Impact

macOS chat gains: full session management (rename/archive/restore/search), visible reasoning and tool activity with a toggle, talk mode + voice notes + read-aloud in the chat surfaces, starter prompts, /verbose that actually sticks, Up/Down input history, reply-with-quote, and drafts that survive session switching. iOS inherits the composer features. Docs updated: docs/platforms/mac/webchat.md.

Evidence

  • swift build --package-path apps/shared/OpenClawKit --target OpenClawChatUI — pass
  • swift test --package-path apps/shared/OpenClawKit --parallel — 48/48 XCTest; Swift Testing 853/856 with 3 pre-existing issues in untouched surfaces (see below)
  • swift build --package-path apps/macos --configuration release — pass
  • swift test --package-path apps/macos --parallel — 1280/1280 pass
  • Gateway contracts verified in-repo: tts.speak (src/gateway/server-methods/tts.ts), sessions.patch verboseLevel (src/gateway/sessions-patch.ts:465)
  • Quote format verified against ui/src/pages/chat/chat-send.ts prependReplyQuote + escape regex
  • Pre-existing OpenClawKitTests failures (not touched by this PR, reproduced identically on two independent checkouts including one with composer-only changes and one with host-only changes): stale pairing-copy expectations (GatewayErrorsTests.swift:59, copy changed in 551c963), watch legacy payload decode (WatchCommandsTests.swift:74, compat added in ec65e10 and lost by a later watch commit), and a load-flaky attachment timeout (passes 9/10 isolated). CI does not run this suite; follow-up task filed to repair it and add coverage.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: macos App: macos size: XL maintainer Maintainer-authored PR labels Jul 17, 2026

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

Copy link
Copy Markdown
Contributor

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: 302dd032e2

ℹ️ 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".

func replaceMessages(_ messages: [OpenClawChatMessage]) {
guard self.messages != messages else { return }
self.messages = messages
self.seedInputHistory(from: messages)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Avoid seeding history from session-clear placeholders

When a user switches back to a session that has transcript history plus local-only entries such as /compact, clearSessionOwnedState() calls replaceMessages([]) after sessionKey already points at the destination session, so this new unconditional seedInputHistory(from: []) resets that session's transcript snapshot without clearing its entries. The next live/cache history load then treats the same transcript rows as new and moves them ahead of the local-only entries, so Up recalls an older transcript message before the more recent local command after a session switch or identity restart. Skip history seeding for the empty clear path, or make the seed operation aware that this is just a view reset rather than an authoritative empty transcript.

Useful? React with 👍 / 👎.

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

Copy link
Copy Markdown
Contributor

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: 0f4718b2fd

ℹ️ 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 on lines +26 to +30
var inputHistoriesBySession: [String: ChatInputHistory] = [:]
/// Unlike web persistence, native drafts stay in memory. Attachments are excluded because
/// the staging guard prevents session switches while they are being prepared.
@ObservationIgnored
var draftsBySession: [String: String] = [:]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Scope composer caches by routing identity

These new composer-history/draft caches are keyed only by sessionKey, but bare keys such as global/main aliases are mutable: syncDeliveryIdentity restarts the transcript when activeAgentId or the routing contract changes while leaving these dictionaries intact. In that case, returning to the same bare key under a different agent/contract can restore a saved draft or Up-arrow history from the previous owner, even though currentSessionSnapshot treats it as a different session. Key these caches by the same routing identity or clear them when the identity changes.

Useful? React with 👍 / 👎.

Comment on lines 490 to 492
.contextMenu {
self.replyMessageButton(for: msg)
Button {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Preserve copy in the speech context menu

When a speech controller is present, listenable assistant messages take this branch, and its context menu still omits copyMessageButton(for:) while the other macOS message branches include it. Since this change now wires speech into the mac chat surfaces, right-clicking an assistant response in the native mac full window/panel shows Reply/Listen but no longer offers Copy Message, regressing the documented copy action for exactly the messages users are most likely to copy.

Useful? React with 👍 / 👎.

@openclaw-barnacle openclaw-barnacle Bot added the app: ios App: ios label Jul 17, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 17, 2026

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

vm.syncDeliveryIdentity(
activeAgentId: routingIdentity.defaultAgentID,
sessionRoutingContract: routingIdentity.contract)

P2 Badge Clear reply targets when routing identity changes

When this snapshot path changes the default agent or routing contract for a bare main/global chat, syncDeliveryIdentity() restarts the transcript through clearSessionOwnedState(), but that session-owned clear path does not clear the new replyTarget. The reply chip can therefore survive after the same visible key is rebound to a different agent/contract, and the next non-slash send will quote a message from the previous routing owner into the new session.

ℹ️ 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".

@openclaw-barnacle openclaw-barnacle Bot added the app: android App: android label Jul 17, 2026
@clawsweeper clawsweeper Bot added P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jul 17, 2026

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

Copy link
Copy Markdown
Contributor

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: b8f75f2e1b

ℹ️ 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".

extension OpenClawChatViewModel {
func recallPreviousInput(caretOnFirstLine: Bool) -> Bool {
var history = self.inputHistoriesBySession[self.sessionKey] ?? ChatInputHistory()
guard history.isRecalling || caretOnFirstLine || self.input.isEmpty else { return false }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Gate history recall on the actual caret start

When a draft is long enough to soft-wrap (or the caret is in the middle of the first hard line) and there is any input history, this guard lets Up-arrow recall a previous message instead of moving the caret within the text view because caretOnFirstLine only checks for preceding newline characters. That can unexpectedly replace the in-progress draft during normal multi-line editing; require the caret to be at the start of the draft, or compute the actual visual first-line boundary, before entering history navigation.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jul 17, 2026
@clawsweeper

clawsweeper Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 17, 2026, 8:19 AM ET / 12:19 UTC.

Summary
The PR adds native macOS session management, assistant traces, speech controls, verbosity forwarding, and shared macOS/iOS composer history, reply quoting, and per-session drafts.

PR surface: Docs +1, Other +4421. Total +4422 across 59 files.

Reproducibility: not applicable. to the feature request itself; however, the four blocking regressions are source-reproducible from the routing-identity, transcript-replacement, outbox-enqueue, and key-routing paths on the current PR head.

Review metrics: 2 noteworthy metrics.

  • Persisted preference defaults: 1 added, default on. The new assistant-trace preference changes the presentation for users who have no stored value, so upgrade intent must be explicit.
  • Session settings passthrough: 1 existing field newly forwarded. Forwarding verboseLevel fixes a dropped setting but changes native client session-patch behavior and needs live persistence proof.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦐 gold shrimp
Patch quality: 🦪 silver shellfish
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Fix all four persistent routing, reply-lifecycle, outbox-flush, and history-boundary findings with focused regression coverage.
  • [P1] Add redacted live proof for speech, history, draft restoration, traces, verbosity persistence, and session mutations.
  • Record the product-owner decision for the default assistant-trace behavior.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: Signed-build screenshots prove starter prompts, toolbar controls, a live gateway roundtrip, and Reply UI, but not microphone capture, Listen playback, history, drafts, actual traces, verbosity persistence, or session mutations; add a redacted recording plus terminal or gateway logs, update the PR body to trigger review, and ask a maintainer to comment @clawsweeper re-review if it does not rerun automatically.

Risk before merge

  • [P1] A reply selected before a mutable routing identity changes can be sent with stale text to a different agent or routing contract.
  • [P1] Accepted messages can remain queued after a session switch because the successful stale-session enqueue path does not guarantee a flush.
  • [P1] Up-arrow history recall can unexpectedly replace an in-progress draft during ordinary first-line or soft-wrapped editing.
  • [P1] Transcript replacement can leave a reply chip targeting deleted or compacted content, causing stale context to be quoted later.
  • [P1] Enabling reasoning and tool traces by default changes existing users' persisted presentation and may expose more operational detail than the previously minimal macOS surface.
  • [P1] The screenshots do not yet prove several high-risk or central behaviors in a real setup, including microphone capture, Listen playback, history and draft restoration, verbosity persistence, and session mutations.

Maintainer options:

  1. Repair state and delivery invariants first (recommended)
    Fix the four persistent review findings, add focused race and lifecycle tests, and obtain the trace-default decision before merging.
  2. Accept the trace presentation change
    A product owner may explicitly accept default-on traces, but the reply, history, and outbox correctness defects still require repair.
  3. Split the parity bundle
    If the combined repair and proof burden remains too broad, retain the host-wiring work and move composer parity into a narrower follow-up PR.

Next step before merge

  • [P1] The four blocking defects are concrete lifecycle and routing repairs that can be addressed mechanically on the PR branch; the worker must leave the trace default unchanged pending the separate product decision.

Maintainer decision needed

  • Question: Should assistant reasoning and tool activity become visible by default in native macOS chat when the user has no stored preference?
  • Rationale: Current macOS behavior hard-disables traces, while the PR introduces a persisted preference whose absent-value behavior enables them for existing and new users; code review cannot choose that disclosure and presentation default safely.
  • Likely owner: steipete — steipete is the documented product owner and authored the default-on trace design in this branch.
  • Options:
    • Preserve minimal default (recommended): Default traces off and let users explicitly enable the persisted toggle, preserving current behavior during upgrade.
    • Enable traces by default: Accept the new default-on presentation for all users without a stored preference and document the intentional behavior change.
    • Differentiate upgrade state: Keep existing installations off while enabling traces for demonstrably fresh installations through an explicit migration or initialization rule.

Security
Cleared: The diff adds no concrete dependency, secret, permission-broadening, downloaded-code, or supply-chain regression; the trace default is a product and compatibility concern rather than a demonstrated authorization boundary break.

Review findings

  • [P1] Clear reply state when routing identity changes — apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift:23
  • [P1] Flush accepted enqueues after a session switch — apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel+Outbox.swift:205
  • [P2] Recall history only at the true draft boundary — apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift:980
Review details

Best possible solution:

Keep the shared host-wiring design, but merge only after composer state is scoped and invalidated with the routing identity, every accepted enqueue schedules delivery, history recall requires a true draft boundary, reply targets track transcript lifetime, the trace default is owner-approved, and the remaining paths have redacted live proof.

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

Not applicable to the feature request itself; however, the four blocking regressions are source-reproducible from the routing-identity, transcript-replacement, outbox-enqueue, and key-routing paths on the current PR head.

Is this the best way to solve the issue?

No, not yet. Reusing shared chat capabilities through the native host is the right architectural direction, but the current lifecycle handling and default-on trace setting make this implementation unsafe to merge without repair and owner approval.

Full review comments:

  • [P1] Clear reply state when routing identity changes — apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift:23
    Still unresolved from the prior cycle: an identity restart can replace the transcript while retaining a reply selected under the previous agent or routing contract, so the next send may quote stale text to a different destination. Clear or re-scope the reply target with the same routing identity used for session-owned state.
    Confidence: 0.98
  • [P1] Flush accepted enqueues after a session switch — apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel+Outbox.swift:205
    Still unresolved from the prior cycle: when enqueue succeeds after the user changes sessions, the stale-session return retires the draft without scheduling an outbox flush. If restore already completed, the accepted message can remain queued indefinitely until another trigger runs.
    Confidence: 0.97
  • [P2] Recall history only at the true draft boundary — apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift:980
    Still unresolved from the prior cycle: caretOnFirstLine only checks for preceding hard newlines, so Up can replace a draft while the caret is mid-line or on a soft-wrapped visual line. Require the caret to be at the actual start of the draft, or compute the native visual boundary.
    Confidence: 0.96
  • [P2] Clear stale reply targets when replacing messages — apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel+TranscriptCache.swift:19
    Still unresolved from the prior cycle: replacing the transcript does not clear a reply target whose message ID disappeared through compaction, reload, or outbox deletion. The next send can therefore quote content no longer visible in the session.
    Confidence: 0.97

Overall correctness: patch is incorrect
Overall confidence: 0.98

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against db3213264a65.

Label changes

Label changes:

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

Label justifications:

  • P1: The unresolved branch defects can mis-associate quoted context or leave an accepted user message queued, affecting core native chat workflows.
  • merge-risk: 🚨 compatibility: The PR introduces a persisted trace preference that defaults on and changes existing native chat presentation when no prior value exists.
  • merge-risk: 🚨 message-delivery: An accepted outbox enqueue can miss its flush after a session switch and remain queued until another trigger occurs.
  • merge-risk: 🚨 session-state: Reply targets, drafts, and history can survive or act across routing and transcript lifecycle boundaries incorrectly.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦐 gold shrimp and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: Signed-build screenshots prove starter prompts, toolbar controls, a live gateway roundtrip, and Reply UI, but not microphone capture, Listen playback, history, drafts, actual traces, verbosity persistence, or session mutations; add a redacted recording plus terminal or gateway logs, update the PR body to trigger review, and ask a maintainer to comment @clawsweeper re-review if it does not rerun automatically.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. Signed-build screenshots prove starter prompts, toolbar controls, a live gateway roundtrip, and Reply UI, but not microphone capture, Listen playback, history, drafts, actual traces, verbosity persistence, or session mutations; add a redacted recording plus terminal or gateway logs, update the PR body to trigger review, and ask a maintainer to comment @clawsweeper re-review if it does not rerun automatically.
Evidence reviewed

PR surface:

Docs +1, Other +4421. Total +4422 across 59 files.

View PR surface stats
Area Files Added Removed Net
Source 0 0 0 0
Tests 0 0 0 0
Docs 1 4 3 +1
Config 0 0 0 0
Generated 0 0 0 0
Other 58 5276 855 +4421
Total 59 5280 858 +4422

Acceptance criteria:

  • [P1] swift test --package-path apps/shared/OpenClawKit --parallel.
  • [P1] swift test --package-path apps/macos --parallel.
  • [P1] swift build --package-path apps/shared/OpenClawKit --target OpenClawChatUI.
  • [P1] swift build --package-path apps/macos --configuration release.

What I checked:

Likely related people:

  • steipete: Repository ownership documentation identifies steipete as the project product owner, and this branch directly authors the macOS/shared-chat parity design and its follow-up repairs. (role: official product owner and feature author; confidence: high; commits: a5dbb09391dd, a987e40cb3fb, b22fb7894aa2; files: apps/macos/Sources/OpenClaw/WebChatSwiftUI.swift, apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift, apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift)
  • tyler6204: Repository ownership documentation lists Tyler Yust for the macOS app, making this the strongest independent routing candidate for the native host, speech, and window integration. (role: macOS app owner; confidence: high; files: apps/macos/Sources/OpenClaw/WebChatSwiftUI.swift, apps/macos/Tests/OpenClawIPCTests/WebChatSwiftUISmokeTests.swift)
  • ngutman: Repository ownership documentation lists Nimrod Gutman for both macOS and iOS apps, relevant because the PR changes shared composer behavior inherited by both clients. (role: macOS and iOS app owner; confidence: high; files: apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift, apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatView.swift, apps/ios/Resources/Localizable.xcstrings)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (5 earlier review cycles)
  • reviewed 2026-07-17T07:51:43.203Z sha b8f75f2 :: needs real behavior proof before merge. :: [P1] Scope composer caches to the routing identity | [P2] Preserve Copy Message when speech actions are available | [P2] Recall history only at the true draft boundary
  • reviewed 2026-07-17T08:44:32.277Z sha b34c877 :: needs real behavior proof before merge. :: [P1] Scope composer caches to the routing identity | [P2] Preserve Copy Message in the speech context menu | [P2] Recall history only at the true draft boundary
  • reviewed 2026-07-17T10:28:31.814Z sha 85c8695 :: needs real behavior proof before merge. :: [P1] Clear reply state when routing identity changes | [P1] Flush accepted enqueues after a session switch | [P2] Recall history only at the true draft boundary
  • reviewed 2026-07-17T10:58:12.797Z sha 53e9ed4 :: needs real behavior proof before merge. :: [P1] Clear reply state when routing identity changes | [P1] Flush accepted enqueues after a session switch | [P2] Recall history only at the true draft boundary
  • reviewed 2026-07-17T11:39:59.002Z sha 53e9ed4 :: needs real behavior proof before merge. :: [P1] Clear reply state when routing identity changes | [P1] Flush accepted enqueues after a session switch | [P2] Recall history only at the true draft boundary | [P2] Clear stale reply targets when replacing messages

@steipete

Copy link
Copy Markdown
Contributor Author

Live test on macOS (signed dev build, real gateway)

Exercised the new capabilities end-to-end on a Mac Studio against a live gateway (latest main build), signed dev app from this branch.

Empty session: starter prompts + intro, voice-note mic and Talk Mode button in the composer

empty state with starter prompts

Toolbar menu: new "Sessions…" manager entry (⇧⌘S) and the persisted "Show reasoning & tool activity" toggle (default on)

toolbar menu

Live send/receive roundtrip with per-message usage metadata

live roundtrip

New per-message context-menu Reply action

context menu reply

Reply chip in the composer (web-parity blockquote goes out on send)

reply chip

Verified live: gateway connect, session create (⌘N), send → streamed reply ("Writing" indicator) → terminal reply with usage line, reply target selection and cancel, starter prompt cards, voice-note and talk controls rendered (mic capture not exercised — needs interactive permission).

@steipete
steipete force-pushed the claude/macos-chat-web-ui-align-b2dd25 branch from b34c877 to f7e72b7 Compare July 17, 2026 09:48

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

Copy link
Copy Markdown
Contributor

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: f7e72b7af8

ℹ️ 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".

}
}

public internal(set) var replyTarget: OpenClawChatReplyTarget?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Clear reply target on routing identity changes

When a mutable session key such as global/main is rebound by syncDeliveryIdentity, the view model restarts via clearSessionOwnedState() without running prepareComposerForSessionSwitch, so this new replyTarget survives while the transcript is replaced under the new agent/contract. A reply chip selected for agent A can therefore remain visible and prepend A's quoted text to the next message sent to agent B; clear the reply target in the identity-restart path as well.

Useful? React with 👍 / 👎.

// Bubble render and flush scheduling stay with the displayed session
// (shipped behavior predating this path); the stored command delivers
// on the next flush trigger, e.g. returning here or a health event.
guard self.isCurrentSession(session) else { return true }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Flush accepted stale-session enqueues

When a healthy text send is routed through the outbox, for example behind existing queued rows, and the user switches sessions while outbox.enqueueCommand is suspended, this success return makes the caller retire the submitted draft via finishAcceptedComposerSend but skips the present/flush block below. If the new session's restore already ran before the row was inserted, no unhealthy→healthy transition occurs to flush it, so the message can sit queued until the user returns to that session or another flush trigger happens; schedule flushOutboxIfNeeded() for accepted stale-session rows before returning.

Useful? React with 👍 / 👎.

@steipete
steipete force-pushed the claude/macos-chat-web-ui-align-b2dd25 branch from f7e72b7 to 85c8695 Compare July 17, 2026 10:24
@clawsweeper clawsweeper Bot added proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jul 17, 2026
@steipete
steipete force-pushed the claude/macos-chat-web-ui-align-b2dd25 branch from 85c8695 to 53e9ed4 Compare July 17, 2026 10:52
@clawsweeper clawsweeper Bot added 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. labels Jul 17, 2026

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

Copy link
Copy Markdown
Contributor

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: 53e9ed4494

ℹ️ 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".

func replaceMessages(_ messages: [OpenClawChatMessage]) {
guard self.messages != messages else { return }
self.messages = messages
self.seedInputHistory(from: messages)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Clear stale reply targets when replacing messages

When a reply chip is selected and the target row is later removed by a transcript replacement, such as deleting a queued outbox bubble or compacting/reloading history, this path updates messages but leaves replyTarget pointing at a UUID that is no longer visible. The next send will still prepend that deleted or compacted text, so users can accidentally quote stale context into a later turn; clear the reply target when its messageID is absent from the replacement set.

Useful? React with 👍 / 👎.

@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 Jul 17, 2026
@steipete
steipete merged commit bf754b8 into main Jul 17, 2026
103 of 105 checks passed
@steipete
steipete deleted the claude/macos-chat-web-ui-align-b2dd25 branch July 17, 2026 12:44
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 18, 2026
…law#109712)

* feat(macos): wire sessions manager, assistant trace, talk, voice notes, and Listen into native chat

* feat(clients): add input history, reply quoting, and per-session drafts to native chat composer

* fix(clients): capture TTS server lease before gateway check and dedupe restored input-history entries

* docs(clients): document reply-chip consume parity with web accepted-send semantics

* fix(clients): retire sent-text recall stash and keep recall markers stable under prepends

* test(clients): wait for outbox restore before asserting live-send paths

* docs(clients): note cross-session outbox flush scheduling contract

* chore(clients): split oversized chat files to satisfy SwiftLint length caps

* chore(i18n): sync native app i18n inventory for new chat strings

* chore: retrigger ci

* chore(i18n): translate new chat strings and regenerate Apple catalogs

* chore(i18n): regenerate Android localization resources for new chat strings

* test(clients): await lifecycle cleanup before modeling replacement gateway traffic

* chore(clients): split invoke timeout helper to satisfy SwiftLint length cap

* chore(clients): drop unused OpenClawProtocol import from invoke timeout split
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: android App: android app: ios App: ios app: macos App: macos docs Improvements or additions to documentation maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P1 High-priority user-facing bug, regression, or broken workflow. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XL 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.

1 participant