feat(ios): add Apple Watch voice turns#100283
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6cc0781d6c
ℹ️ 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".
| private func scheduleVoiceReplyTimeout() { | ||
| self.voiceReplyTimeout?.cancel() | ||
| self.voiceReplyTimeout = Task { @MainActor in | ||
| try? await Task.sleep(for: .seconds(90)) |
There was a problem hiding this comment.
Keep voice waits alive for queued sends
Because sendChatMessage returns the command id before the async receiver.sendAppCommand result is known, voice turns also enter this path when WatchConnectivity falls back to queued transferUserInfo. Starting a fixed 90s timeout here means any queued delivery that reaches the iPhone more than ~15s late (the iPhone then waits up to 75s for the run) cancels the tracker before the watch.chat.completion arrives, so the completion is ignored instead of spoken; base the timeout on actual delivery/result or keep queued voice turns pending longer.
Useful? React with 👍 / 👎.
|
|
||
| ### Changes | ||
|
|
||
| - **Apple Watch voice turns:** dictate a message from the Watch chat and hear the new OpenClaw reply spoken on the Watch, with explicit silent-message and stop-speaking controls. (#100224) |
There was a problem hiding this comment.
Remove feature entry from release-owned changelog
AGENTS.md marks CHANGELOG.md as release-only and says normal feat/fix work should put release-note context in the PR body or commit, with release generation deriving entries later. Adding this issue-level feature note directly will make the generated release notes stale or duplicated when the release job rebuilds this section, so this entry should be removed from the normal feature commit.
Useful? React with 👍 / 👎.
29b1952 to
fc74753
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc74753964
ℹ️ 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".
| return "Speaking reply…" | ||
| } | ||
| if self.voiceTurnTracker.isAwaitingReply { | ||
| return "Waiting for spoken reply…" |
There was a problem hiding this comment.
Add the voice strings to native i18n
These new Watch UI strings are returned from a String? computed property, while scripts/native-app-i18n.ts only extracts direct SwiftUI/modifier literals or var ...: String switch branches; the updated apps/.i18n/native-source.json contains only line-number shifts and no entries for “Speaking reply…”/“Waiting for spoken reply…”. On localized watchOS builds the new voice states remain English, so expose them through an extracted/localized string path or update the inventory.
Useful? React with 👍 / 👎.
|
Codex review: needs real behavior proof before merge. Reviewed July 5, 2026, 9:18 AM ET / 13:18 UTC. Summary PR surface: Docs +1, Other +671. Total +672 across 17 files. Reproducibility: yes. for the review findings from source inspection: the PR head starts a fixed Watch timeout before delivery is known and uses broad fallback reply matching after the submitted row. I did not execute watchOS flows in this read-only review. Review metrics: 2 noteworthy metrics.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review findings
Review detailsBest possible solution: Land only after reply matching is command/turn-bound, queued voice waits survive delayed WatchConnectivity delivery, voice strings and release-note handling follow repo policy, and redacted real Watch or simulator proof shows the voice turn path. Do we have a high-confidence way to reproduce the issue? Yes for the review findings from source inspection: the PR head starts a fixed Watch timeout before delivery is known and uses broad fallback reply matching after the submitted row. I did not execute watchOS flows in this read-only review. Is this the best way to solve the issue? No, not yet: reusing Watch dictation and WatchConnectivity is a plausible owner-boundary solution, but the current implementation must tighten turn correlation, localization, and release-note handling before it is the best maintainable fix. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against f9e194e4a122. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Docs +1, Other +671. Total +672 across 17 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
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
Review history (1 earlier review cycle)
|
|
Land-ready proof for
Known proof gap: simulator validation cannot exercise physical Watch microphone dictation or speaker acoustics; those use WatchKit/AVFoundation system APIs and the surrounding state/correlation paths are covered above. |
ef7343a to
6b93d9f
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6b93d9fa25
ℹ️ 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".
| return entries[(userIndex + 1)...].first(where: { | ||
| self.isTerminalWatchAssistant($0) | ||
| })?.text |
There was a problem hiding this comment.
Stop voice reply search at the next user turn
When the fallback cannot match an assistant row by run id, this searches all messages after the matched Watch user row and speaks the first terminal assistant message, even if another user turn appears before it. In a delayed/queued Watch send where the user asks something from the iPhone before the Watch run finishes, the next assistant reply can belong to that later user turn and will be spoken as the Watch voice reply; bound the search to the current user turn, as the chat history reconciliation path does, instead of crossing subsequent user rows.
Useful? React with 👍 / 👎.
6b93d9f to
28ef91d
Compare
28ef91d to
5977a97
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5977a97b50
ℹ️ 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".
| else { | ||
| return false | ||
| } | ||
| return entry.text.contains(submittedText) |
There was a problem hiding this comment.
Avoid anchoring queued voice replies by substring
When the exact runId:user row is missing (the collected queued path this fallback is meant to cover), lastIndex plus entry.text.contains(submittedText) can anchor a short dictated Watch message like “ok” to a later iPhone/user turn that happens to contain that text after submittedAtMs. The reply lookup then speaks that later turn’s assistant response for the Watch command; use a stronger queued-turn marker or avoid selecting later unrelated user rows by substring.
Useful? React with 👍 / 👎.
e5812f2 to
2cf9651
Compare
2cf9651 to
e90c5ac
Compare
|
Merged via squash.
|
* feat(ios): add Apple Watch voice turns * chore(ios): sync native i18n inventory * fix(ios): preserve Watch message label
Closes #100224
What Problem This Solves
Apple Watch chat accepts dictated text, but replies remain visual-only. Users cannot complete a hands-free voice turn from the Watch.
Why This Change Was Made
Adds an explicit voice-turn action that uses native Watch dictation, the existing WatchConnectivity chat path, and native speech playback for the matching completed assistant reply. The existing Message action remains silent; intermediate tool progress is not spoken, and users can cancel while waiting or stop playback.
User Impact
Users can tap the microphone on Apple Watch, dictate a message, and hear OpenClaw's final reply spoken back. Delivery survives temporary Watch reachability changes through the existing durable WatchConnectivity path.
Evidence
xcodebuild test -project apps/ios/OpenClaw.xcodeproj -scheme OpenClaw -destination 'platform=iOS Simulator,id=504AD0F4-BA3E-4012-B7CB-C45A1F613984' -only-testing:OpenClawTests/NodeAppModelInvokeTests— 87 tests passed.xcodebuild test -project apps/ios/OpenClaw.xcodeproj -scheme OpenClawLogicTests -destination 'platform=macOS' -only-testing:OpenClawLogicTests/WatchVoiceTurnTrackerTests— 3 tests passed.xcodebuild build -project apps/ios/OpenClaw.xcodeproj -scheme OpenClawWatchApp -destination 'platform=watchOS Simulator,id=1173986F-82CA-463A-B461-7C3D569E01A0'— succeeded.