Skip to content

Commit 0af3118

Browse files
fix: harden talk silence timeout parsing (#39607) (thanks @danodoesdesign)
Co-authored-by: dano does design <dano.does.design@gmail.com>
1 parent 6ff7e8f commit 0af3118

File tree

5 files changed

+38
-18
lines changed

5 files changed

+38
-18
lines changed

.secrets.baseline

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9809,49 +9809,49 @@
98099809
"filename": "docs/gateway/configuration-reference.md",
98109810
"hashed_secret": "7f8aaf142ce0552c260f2e546dda43ddd7c9aef3",
98119811
"is_verified": false,
9812-
"line_number": 1813
9812+
"line_number": 1815
98139813
},
98149814
{
98159815
"type": "Secret Keyword",
98169816
"filename": "docs/gateway/configuration-reference.md",
98179817
"hashed_secret": "22af290a1a3d5e941193a41a3d3a9e4ca8da5e27",
98189818
"is_verified": false,
9819-
"line_number": 1986
9819+
"line_number": 1988
98209820
},
98219821
{
98229822
"type": "Secret Keyword",
98239823
"filename": "docs/gateway/configuration-reference.md",
98249824
"hashed_secret": "ec3810e10fb78db55ce38b9c18d1c3eb1db739e0",
98259825
"is_verified": false,
9826-
"line_number": 2042
9826+
"line_number": 2044
98279827
},
98289828
{
98299829
"type": "Secret Keyword",
98309830
"filename": "docs/gateway/configuration-reference.md",
98319831
"hashed_secret": "c1e6ee547fd492df1441ac492e8bb294974712bd",
98329832
"is_verified": false,
9833-
"line_number": 2274
9833+
"line_number": 2276
98349834
},
98359835
{
98369836
"type": "Secret Keyword",
98379837
"filename": "docs/gateway/configuration-reference.md",
98389838
"hashed_secret": "45d676e7c6ab44cf4b8fa366ef2d8fccd3e6d6e6",
98399839
"is_verified": false,
9840-
"line_number": 2402
9840+
"line_number": 2404
98419841
},
98429842
{
98439843
"type": "Secret Keyword",
98449844
"filename": "docs/gateway/configuration-reference.md",
98459845
"hashed_secret": "a219d7693c25cd2d93313512e200ff3eb374d281",
98469846
"is_verified": false,
9847-
"line_number": 2655
9847+
"line_number": 2657
98489848
},
98499849
{
98509850
"type": "Secret Keyword",
98519851
"filename": "docs/gateway/configuration-reference.md",
98529852
"hashed_secret": "b6f56e5e92078ed7c078c46fbfeedcbe5719bc25",
98539853
"is_verified": false,
9854-
"line_number": 2657
9854+
"line_number": 2659
98559855
}
98569856
],
98579857
"docs/gateway/configuration.md": [
@@ -10198,21 +10198,21 @@
1019810198
"filename": "docs/tools/web.md",
1019910199
"hashed_secret": "6b26c117c66a0c030e239eef595c1e18865132a8",
1020010200
"is_verified": false,
10201-
"line_number": 90
10201+
"line_number": 129
1020210202
},
1020310203
{
1020410204
"type": "Secret Keyword",
1020510205
"filename": "docs/tools/web.md",
1020610206
"hashed_secret": "491d458f895b9213facb2ee9375b1b044eaea3ac",
1020710207
"is_verified": false,
10208-
"line_number": 179
10208+
"line_number": 202
1020910209
},
1021010210
{
1021110211
"type": "Secret Keyword",
1021210212
"filename": "docs/tools/web.md",
1021310213
"hashed_secret": "674397e2c0c2faaa85961c708d2a96a7cc7af217",
1021410214
"is_verified": false,
10215-
"line_number": 277
10215+
"line_number": 303
1021610216
}
1021710217
],
1021810218
"docs/tts.md": [
@@ -11583,7 +11583,7 @@
1158311583
"filename": "src/agents/pi-embedded-runner/model.ts",
1158411584
"hashed_secret": "e774aaeac31c6272107ba89080295e277050fa7c",
1158511585
"is_verified": false,
11586-
"line_number": 272
11586+
"line_number": 267
1158711587
}
1158811588
],
1158911589
"src/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.ts": [
@@ -11680,7 +11680,7 @@
1168011680
"filename": "src/agents/tools/web-search.ts",
1168111681
"hashed_secret": "dfba7aade0868074c2861c98e2a9a92f3178a51b",
1168211682
"is_verified": false,
11683-
"line_number": 254
11683+
"line_number": 266
1168411684
}
1168511685
],
1168611686
"src/agents/tools/web-tools.enabled-defaults.e2e.test.ts": [
@@ -12335,14 +12335,14 @@
1233512335
"filename": "src/config/schema.help.ts",
1233612336
"hashed_secret": "9f4cda226d3868676ac7f86f59e4190eb94bd208",
1233712337
"is_verified": false,
12338-
"line_number": 649
12338+
"line_number": 651
1233912339
},
1234012340
{
1234112341
"type": "Secret Keyword",
1234212342
"filename": "src/config/schema.help.ts",
1234312343
"hashed_secret": "01822c8bbf6a8b136944b14182cb885100ec2eae",
1234412344
"is_verified": false,
12345-
"line_number": 680
12345+
"line_number": 684
1234612346
}
1234712347
],
1234812348
"src/config/schema.irc.ts": [
@@ -12388,7 +12388,7 @@
1238812388
"filename": "src/config/schema.labels.ts",
1238912389
"hashed_secret": "2eda7cd978f39eebec3bf03e4410a40e14167fff",
1239012390
"is_verified": false,
12391-
"line_number": 324
12391+
"line_number": 325
1239212392
}
1239312393
],
1239412394
"src/config/slack-http-config.test.ts": [
@@ -13034,5 +13034,5 @@
1303413034
}
1303513035
]
1303613036
},
13037-
"generated_at": "2026-03-08T13:52:40Z"
13037+
"generated_at": "2026-03-08T14:28:30Z"
1303813038
}

apps/android/app/src/main/java/ai/openclaw/app/voice/TalkModeManager.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ class TalkModeManager(
107107
}
108108

109109
internal fun resolvedSilenceTimeoutMs(talk: JsonObject?): Long {
110-
val timeout = talk?.get("silenceTimeoutMs").asDoubleOrNull() ?: return defaultSilenceTimeoutMs
110+
val primitive = talk?.get("silenceTimeoutMs") as? JsonPrimitive ?: return defaultSilenceTimeoutMs
111+
if (primitive.isString) return defaultSilenceTimeoutMs
112+
val timeout = primitive.content.toDoubleOrNull() ?: return defaultSilenceTimeoutMs
111113
if (timeout <= 0 || timeout % 1.0 != 0.0 || timeout > Long.MAX_VALUE.toDouble()) {
112114
return defaultSilenceTimeoutMs
113115
}

apps/android/app/src/test/java/ai/openclaw/app/voice/TalkModeConfigParsingTest.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,11 @@ class TalkModeConfigParsingTest {
7373

7474
assertEquals(700L, TalkModeManager.resolvedSilenceTimeoutMs(talk))
7575
}
76+
77+
@Test
78+
fun defaultsSilenceTimeoutMsWhenString() {
79+
val talk = buildJsonObject { put("silenceTimeoutMs", "1500") }
80+
81+
assertEquals(700L, TalkModeManager.resolvedSilenceTimeoutMs(talk))
82+
}
7683
}

apps/ios/Sources/Voice/TalkModeManager.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ final class TalkModeManager: NSObject {
9898

9999
private var gateway: GatewayNodeSession?
100100
private var gatewayConnected = false
101-
private var silenceWindow: TimeInterval = TimeInterval(Self.defaultSilenceTimeoutMs) / 1000
101+
private var silenceWindow: TimeInterval = TimeInterval(TalkModeManager.defaultSilenceTimeoutMs) / 1000
102102
private var lastAudioActivity: Date?
103103
private var noiseFloorSamples: [Double] = []
104104
private var noiseFloor: Double?
@@ -2010,6 +2010,9 @@ extension TalkModeManager {
20102010
where timeout > 0 && timeout.rounded(.towardZero) == timeout && timeout <= Double(Int.max):
20112011
return Int(timeout)
20122012
case let timeout as NSNumber:
2013+
if CFGetTypeID(timeout) == CFBooleanGetTypeID() {
2014+
return Self.defaultSilenceTimeoutMs
2015+
}
20132016
let value = timeout.doubleValue
20142017
if value > 0 && value.rounded(.towardZero) == value && value <= Double(Int.max) {
20152018
return Int(value)

apps/ios/Tests/TalkModeConfigParsingTests.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,12 @@ import Testing
6767

6868
#expect(TalkModeManager.resolvedSilenceTimeoutMs(talk) == 900)
6969
}
70+
71+
@Test func defaultsSilenceTimeoutMsWhenBool() {
72+
let talk: [String: Any] = [
73+
"silenceTimeoutMs": true,
74+
]
75+
76+
#expect(TalkModeManager.resolvedSilenceTimeoutMs(talk) == 900)
77+
}
7078
}

0 commit comments

Comments
 (0)