Skip to content

Commit 245092d

Browse files
authored
feat(ios): add Apple Watch voice turns (#100283)
* feat(ios): add Apple Watch voice turns * chore(ios): sync native i18n inventory * fix(ios): preserve Watch message label
1 parent 4c42815 commit 245092d

17 files changed

Lines changed: 783 additions & 111 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Docs: https://docs.openclaw.ai
2929
### Changes
3030

3131
- **Control UI context usage:** show context-window progress, latest-run input/output tokens, and the active model when the chat context ring is opened.
32+
- **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)
3233
- **Conversational onboarding:** add a real agent-loop Crestodian setup flow across the CLI, Gateway, web install, and macOS app, with typed operations, exact approval binding, masked credential prompts, isolated session transcripts, and safe handoff to the normal agent.
3334
- **Generated session titles:** name new Control UI sessions from their first message, and add default/per-agent `utilityModel` routing for lower-cost session, topic, and thread title generation. Thanks @Juliangsm and @zhangguiping-xydt.
3435
- **ClawRouter routing and quotas:** add the bundled ClawRouter provider plugin with credential-scoped dynamic model discovery, OpenAI-compatible and native Anthropic/Gemini transports, and managed budget reporting across OpenClaw usage surfaces. (#99658)

apps/.i18n/native-source.json

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10995,63 +10995,63 @@
1099510995
},
1099610996
{
1099710997
"kind": "conditional-branch",
10998-
"line": 2296,
10998+
"line": 2319,
1099910999
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
1100011000
"source": "Action required",
1100111001
"surface": "apple",
1100211002
"id": "native.apple.0d030e96f7738497"
1100311003
},
1100411004
{
1100511005
"kind": "conditional-branch",
11006-
"line": 2296,
11006+
"line": 2319,
1100711007
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
1100811008
"source": "Approval needed",
1100911009
"surface": "apple",
1101011010
"id": "native.apple.ce6a022159f2fb41"
1101111011
},
1101211012
{
1101311013
"kind": "conditional-branch",
11014-
"line": 2629,
11014+
"line": 2652,
1101511015
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
1101611016
"source": "Connecting…",
1101711017
"surface": "apple",
1101811018
"id": "native.apple.b0d9c1ba8ef7ec19"
1101911019
},
1102011020
{
1102111021
"kind": "conditional-branch",
11022-
"line": 2629,
11022+
"line": 2652,
1102311023
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
1102411024
"source": "Reconnecting…",
1102511025
"surface": "apple",
1102611026
"id": "native.apple.bd98e19b49309284"
1102711027
},
1102811028
{
1102911029
"kind": "conditional-branch",
11030-
"line": 2633,
11030+
"line": 2656,
1103111031
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
1103211032
"source": "Connecting...",
1103311033
"surface": "apple",
1103411034
"id": "native.apple.6504753f3621269e"
1103511035
},
1103611036
{
1103711037
"kind": "conditional-branch",
11038-
"line": 2633,
11038+
"line": 2656,
1103911039
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
1104011040
"source": "Reconnecting...",
1104111041
"surface": "apple",
1104211042
"id": "native.apple.c7fbe2a713d78714"
1104311043
},
1104411044
{
1104511045
"kind": "conditional-branch",
11046-
"line": 2941,
11046+
"line": 2964,
1104711047
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
1104811048
"source": "Connected",
1104911049
"surface": "apple",
1105011050
"id": "native.apple.c0a005f81d588867"
1105111051
},
1105211052
{
1105311053
"kind": "conditional-branch",
11054-
"line": 2941,
11054+
"line": 2964,
1105511055
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
1105611056
"source": "Offline",
1105711057
"surface": "apple",
@@ -12547,255 +12547,255 @@
1254712547
},
1254812548
{
1254912549
"kind": "conditional-branch",
12550-
"line": 327,
12550+
"line": 329,
1255112551
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1255212552
"source": "\\(self.chatCount)",
1255312553
"surface": "apple",
1255412554
"id": "native.apple.00d2c14f9f635100"
1255512555
},
1255612556
{
1255712557
"kind": "conditional-branch",
12558-
"line": 331,
12558+
"line": 333,
1255912559
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1256012560
"source": "\\(self.approvalCount)",
1256112561
"surface": "apple",
1256212562
"id": "native.apple.c3f1a9e79f6e0e97"
1256312563
},
1256412564
{
1256512565
"kind": "conditional-branch",
12566-
"line": 336,
12566+
"line": 338,
1256712567
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1256812568
"source": "AI agent online",
1256912569
"surface": "apple",
1257012570
"id": "native.apple.eb8d87882ee9d932"
1257112571
},
1257212572
{
1257312573
"kind": "conditional-branch",
12574-
"line": 336,
12574+
"line": 338,
1257512575
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1257612576
"source": "Reconnect on iPhone",
1257712577
"surface": "apple",
1257812578
"id": "native.apple.1fed99e43ac07133"
1257912579
},
1258012580
{
1258112581
"kind": "conditional-branch",
12582-
"line": 343,
12582+
"line": 345,
1258312583
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1258412584
"source": "Pairing",
1258512585
"surface": "apple",
1258612586
"id": "native.apple.a240e731ca37dbdd"
1258712587
},
1258812588
{
1258912589
"kind": "conditional-branch",
12590-
"line": 343,
12590+
"line": 345,
1259112591
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1259212592
"source": "Running",
1259312593
"surface": "apple",
1259412594
"id": "native.apple.381d10256d49d0e0"
1259512595
},
1259612596
{
1259712597
"kind": "conditional-branch",
12598-
"line": 363,
12598+
"line": 365,
1259912599
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1260012600
"source": "Ready for quick actions",
1260112601
"surface": "apple",
1260212602
"id": "native.apple.643a9402efef3924"
1260312603
},
1260412604
{
1260512605
"kind": "conditional-branch",
12606-
"line": 363,
12606+
"line": 365,
1260712607
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1260812608
"source": "Waiting for iPhone sync",
1260912609
"surface": "apple",
1261012610
"id": "native.apple.e927c0240dd8ab4b"
1261112611
},
1261212612
{
1261312613
"kind": "conditional-branch",
12614-
"line": 367,
12614+
"line": 369,
1261512615
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1261612616
"source": "1 approval waiting",
1261712617
"surface": "apple",
1261812618
"id": "native.apple.6a607ff2270f7234"
1261912619
},
1262012620
{
1262112621
"kind": "conditional-branch",
12622-
"line": 367,
12622+
"line": 369,
1262312623
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1262412624
"source": "\\(self.approvalCount) approvals",
1262512625
"surface": "apple",
1262612626
"id": "native.apple.046272dd8fbd45cd"
1262712627
},
1262812628
{
1262912629
"kind": "conditional-branch",
12630-
"line": 376,
12630+
"line": 378,
1263112631
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1263212632
"source": "Decide from watch",
1263312633
"surface": "apple",
1263412634
"id": "native.apple.c938aa514b77854a"
1263512635
},
1263612636
{
1263712637
"kind": "conditional-branch",
12638-
"line": 376,
12638+
"line": 378,
1263912639
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1264012640
"source": "No approvals",
1264112641
"surface": "apple",
1264212642
"id": "native.apple.0201a3557b1a8a4a"
1264312643
},
1264412644
{
1264512645
"kind": "conditional-branch",
12646-
"line": 430,
12646+
"line": 432,
1264712647
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1264812648
"source": "1 recent message",
1264912649
"surface": "apple",
1265012650
"id": "native.apple.84674ce9751faffd"
1265112651
},
1265212652
{
1265312653
"kind": "conditional-branch",
12654-
"line": 430,
12654+
"line": 432,
1265512655
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1265612656
"source": "\\(self.chatCount) recent messages",
1265712657
"surface": "apple",
1265812658
"id": "native.apple.1495106ee09cc268"
1265912659
},
1266012660
{
1266112661
"kind": "conditional-branch",
12662-
"line": 432,
12662+
"line": 434,
1266312663
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1266412664
"source": "No messages synced",
1266512665
"surface": "apple",
1266612666
"id": "native.apple.2b7032e200b1d495"
1266712667
},
1266812668
{
1266912669
"kind": "conditional-branch",
12670-
"line": 462,
12670+
"line": 464,
1267112671
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1267212672
"source": "Synced",
1267312673
"surface": "apple",
1267412674
"id": "native.apple.5e32bb776eec9d39"
1267512675
},
1267612676
{
1267712677
"kind": "conditional-branch",
12678-
"line": 462,
12678+
"line": 464,
1267912679
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1268012680
"source": "Waiting for iPhone",
1268112681
"surface": "apple",
1268212682
"id": "native.apple.e3a9d9067b1ccf6a"
1268312683
},
1268412684
{
1268512685
"kind": "ui-named-argument",
12686-
"line": 728,
12686+
"line": 730,
1268712687
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1268812688
"source": "Inbox",
1268912689
"surface": "apple",
1269012690
"id": "native.apple.fadaa0ca97ba0c43"
1269112691
},
1269212692
{
1269312693
"kind": "ui-named-argument",
12694-
"line": 904,
12694+
"line": 906,
1269512695
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1269612696
"source": "OpenClaw",
1269712697
"surface": "apple",
1269812698
"id": "native.apple.3fdc651e507de84b"
1269912699
},
1270012700
{
1270112701
"kind": "conditional-branch",
12702-
"line": 993,
12702+
"line": 995,
1270312703
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1270412704
"source": "You",
1270512705
"surface": "apple",
1270612706
"id": "native.apple.337c2164038d1a5a"
1270712707
},
1270812708
{
1270912709
"kind": "conditional-branch",
12710-
"line": 995,
12710+
"line": 997,
1271112711
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1271212712
"source": "System",
1271312713
"surface": "apple",
1271412714
"id": "native.apple.a8cfe6cb5bc33c21"
1271512715
},
1271612716
{
1271712717
"kind": "ui-named-argument",
12718-
"line": 1031,
12718+
"line": 1042,
1271912719
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1272012720
"source": "Refresh",
1272112721
"surface": "apple",
1272212722
"id": "native.apple.c1de056da9ee1b27"
1272312723
},
1272412724
{
1272512725
"kind": "ui-call",
12726-
"line": 1065,
12726+
"line": 1137,
1272712727
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1272812728
"source": "No chat synced",
1272912729
"surface": "apple",
1273012730
"id": "native.apple.5f277949dc42b1c3"
1273112731
},
1273212732
{
1273312733
"kind": "ui-call",
12734-
"line": 1072,
12734+
"line": 1144,
1273512735
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1273612736
"source": "Tap the message pill below to start from your watch.",
1273712737
"surface": "apple",
1273812738
"id": "native.apple.9119276e0f1b473d"
1273912739
},
1274012740
{
1274112741
"kind": "ui-call",
12742-
"line": 1114,
12742+
"line": 1192,
1274312743
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1274412744
"source": "Message OpenClaw",
1274512745
"surface": "apple",
1274612746
"id": "native.apple.b816e4b9e492ae6c"
1274712747
},
1274812748
{
1274912749
"kind": "ui-named-argument",
12750-
"line": 1179,
12750+
"line": 1295,
1275112751
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1275212752
"source": "Approvals",
1275312753
"surface": "apple",
1275412754
"id": "native.apple.f3ccbf04d80cf021"
1275512755
},
1275612756
{
1275712757
"kind": "ui-named-argument",
12758-
"line": 1182,
12758+
"line": 1298,
1275912759
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1276012760
"source": "Clear",
1276112761
"surface": "apple",
1276212762
"id": "native.apple.fde372bcd0305149"
1276312763
},
1276412764
{
1276512765
"kind": "ui-named-argument",
12766-
"line": 1183,
12766+
"line": 1299,
1276712767
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1276812768
"source": "No approvals waiting",
1276912769
"surface": "apple",
1277012770
"id": "native.apple.30184946721b66e9"
1277112771
},
1277212772
{
1277312773
"kind": "ui-named-argument",
12774-
"line": 1243,
12774+
"line": 1359,
1277512775
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1277612776
"source": "Approval",
1277712777
"surface": "apple",
1277812778
"id": "native.apple.ef3ff87537a32741"
1277912779
},
1278012780
{
1278112781
"kind": "ui-named-argument",
12782-
"line": 1257,
12782+
"line": 1373,
1278312783
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1278412784
"source": "Sending decision...",
1278512785
"surface": "apple",
1278612786
"id": "native.apple.24aa28fc8c954704"
1278712787
},
1278812788
{
1278912789
"kind": "ui-named-argument",
12790-
"line": 1261,
12790+
"line": 1377,
1279112791
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1279212792
"source": "Approve",
1279312793
"surface": "apple",
1279412794
"id": "native.apple.b7b88bee2f79f10e"
1279512795
},
1279612796
{
1279712797
"kind": "ui-named-argument",
12798-
"line": 1267,
12798+
"line": 1383,
1279912799
"path": "apps/ios/WatchApp/Sources/WatchInboxView.swift",
1280012800
"source": "Deny",
1280112801
"surface": "apple",

apps/ios/Sources/Chat/AppleReviewDemoChatTransport.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,8 @@ private actor LocalFixtureChatStore {
399399
content: nil),
400400
],
401401
timestamp: timestamp,
402-
idempotencyKey: idempotencyKey)
402+
idempotencyKey: idempotencyKey,
403+
stopReason: role == "assistant" ? "stop" : nil)
403404
}
404405

405406
private static func normalizedSessionKey(_ value: String, fallback: String) -> String {

0 commit comments

Comments
 (0)