mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix: harden talk silence timeout parsing (#39607) (thanks @danodoesdesign)
Co-authored-by: dano does design <dano.does.design@gmail.com>
This commit is contained in:
@@ -9809,49 +9809,49 @@
|
||||
"filename": "docs/gateway/configuration-reference.md",
|
||||
"hashed_secret": "7f8aaf142ce0552c260f2e546dda43ddd7c9aef3",
|
||||
"is_verified": false,
|
||||
"line_number": 1813
|
||||
"line_number": 1815
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "docs/gateway/configuration-reference.md",
|
||||
"hashed_secret": "22af290a1a3d5e941193a41a3d3a9e4ca8da5e27",
|
||||
"is_verified": false,
|
||||
"line_number": 1986
|
||||
"line_number": 1988
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "docs/gateway/configuration-reference.md",
|
||||
"hashed_secret": "ec3810e10fb78db55ce38b9c18d1c3eb1db739e0",
|
||||
"is_verified": false,
|
||||
"line_number": 2042
|
||||
"line_number": 2044
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "docs/gateway/configuration-reference.md",
|
||||
"hashed_secret": "c1e6ee547fd492df1441ac492e8bb294974712bd",
|
||||
"is_verified": false,
|
||||
"line_number": 2274
|
||||
"line_number": 2276
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "docs/gateway/configuration-reference.md",
|
||||
"hashed_secret": "45d676e7c6ab44cf4b8fa366ef2d8fccd3e6d6e6",
|
||||
"is_verified": false,
|
||||
"line_number": 2402
|
||||
"line_number": 2404
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "docs/gateway/configuration-reference.md",
|
||||
"hashed_secret": "a219d7693c25cd2d93313512e200ff3eb374d281",
|
||||
"is_verified": false,
|
||||
"line_number": 2655
|
||||
"line_number": 2657
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "docs/gateway/configuration-reference.md",
|
||||
"hashed_secret": "b6f56e5e92078ed7c078c46fbfeedcbe5719bc25",
|
||||
"is_verified": false,
|
||||
"line_number": 2657
|
||||
"line_number": 2659
|
||||
}
|
||||
],
|
||||
"docs/gateway/configuration.md": [
|
||||
@@ -10198,21 +10198,21 @@
|
||||
"filename": "docs/tools/web.md",
|
||||
"hashed_secret": "6b26c117c66a0c030e239eef595c1e18865132a8",
|
||||
"is_verified": false,
|
||||
"line_number": 90
|
||||
"line_number": 129
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "docs/tools/web.md",
|
||||
"hashed_secret": "491d458f895b9213facb2ee9375b1b044eaea3ac",
|
||||
"is_verified": false,
|
||||
"line_number": 179
|
||||
"line_number": 202
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "docs/tools/web.md",
|
||||
"hashed_secret": "674397e2c0c2faaa85961c708d2a96a7cc7af217",
|
||||
"is_verified": false,
|
||||
"line_number": 277
|
||||
"line_number": 303
|
||||
}
|
||||
],
|
||||
"docs/tts.md": [
|
||||
@@ -11583,7 +11583,7 @@
|
||||
"filename": "src/agents/pi-embedded-runner/model.ts",
|
||||
"hashed_secret": "e774aaeac31c6272107ba89080295e277050fa7c",
|
||||
"is_verified": false,
|
||||
"line_number": 272
|
||||
"line_number": 267
|
||||
}
|
||||
],
|
||||
"src/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.ts": [
|
||||
@@ -11680,7 +11680,7 @@
|
||||
"filename": "src/agents/tools/web-search.ts",
|
||||
"hashed_secret": "dfba7aade0868074c2861c98e2a9a92f3178a51b",
|
||||
"is_verified": false,
|
||||
"line_number": 254
|
||||
"line_number": 266
|
||||
}
|
||||
],
|
||||
"src/agents/tools/web-tools.enabled-defaults.e2e.test.ts": [
|
||||
@@ -12335,14 +12335,14 @@
|
||||
"filename": "src/config/schema.help.ts",
|
||||
"hashed_secret": "9f4cda226d3868676ac7f86f59e4190eb94bd208",
|
||||
"is_verified": false,
|
||||
"line_number": 649
|
||||
"line_number": 651
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "src/config/schema.help.ts",
|
||||
"hashed_secret": "01822c8bbf6a8b136944b14182cb885100ec2eae",
|
||||
"is_verified": false,
|
||||
"line_number": 680
|
||||
"line_number": 684
|
||||
}
|
||||
],
|
||||
"src/config/schema.irc.ts": [
|
||||
@@ -12388,7 +12388,7 @@
|
||||
"filename": "src/config/schema.labels.ts",
|
||||
"hashed_secret": "2eda7cd978f39eebec3bf03e4410a40e14167fff",
|
||||
"is_verified": false,
|
||||
"line_number": 324
|
||||
"line_number": 325
|
||||
}
|
||||
],
|
||||
"src/config/slack-http-config.test.ts": [
|
||||
@@ -13034,5 +13034,5 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"generated_at": "2026-03-08T13:52:40Z"
|
||||
"generated_at": "2026-03-08T14:28:30Z"
|
||||
}
|
||||
|
||||
@@ -107,7 +107,9 @@ class TalkModeManager(
|
||||
}
|
||||
|
||||
internal fun resolvedSilenceTimeoutMs(talk: JsonObject?): Long {
|
||||
val timeout = talk?.get("silenceTimeoutMs").asDoubleOrNull() ?: return defaultSilenceTimeoutMs
|
||||
val primitive = talk?.get("silenceTimeoutMs") as? JsonPrimitive ?: return defaultSilenceTimeoutMs
|
||||
if (primitive.isString) return defaultSilenceTimeoutMs
|
||||
val timeout = primitive.content.toDoubleOrNull() ?: return defaultSilenceTimeoutMs
|
||||
if (timeout <= 0 || timeout % 1.0 != 0.0 || timeout > Long.MAX_VALUE.toDouble()) {
|
||||
return defaultSilenceTimeoutMs
|
||||
}
|
||||
|
||||
@@ -73,4 +73,11 @@ class TalkModeConfigParsingTest {
|
||||
|
||||
assertEquals(700L, TalkModeManager.resolvedSilenceTimeoutMs(talk))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun defaultsSilenceTimeoutMsWhenString() {
|
||||
val talk = buildJsonObject { put("silenceTimeoutMs", "1500") }
|
||||
|
||||
assertEquals(700L, TalkModeManager.resolvedSilenceTimeoutMs(talk))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ final class TalkModeManager: NSObject {
|
||||
|
||||
private var gateway: GatewayNodeSession?
|
||||
private var gatewayConnected = false
|
||||
private var silenceWindow: TimeInterval = TimeInterval(Self.defaultSilenceTimeoutMs) / 1000
|
||||
private var silenceWindow: TimeInterval = TimeInterval(TalkModeManager.defaultSilenceTimeoutMs) / 1000
|
||||
private var lastAudioActivity: Date?
|
||||
private var noiseFloorSamples: [Double] = []
|
||||
private var noiseFloor: Double?
|
||||
@@ -2010,6 +2010,9 @@ extension TalkModeManager {
|
||||
where timeout > 0 && timeout.rounded(.towardZero) == timeout && timeout <= Double(Int.max):
|
||||
return Int(timeout)
|
||||
case let timeout as NSNumber:
|
||||
if CFGetTypeID(timeout) == CFBooleanGetTypeID() {
|
||||
return Self.defaultSilenceTimeoutMs
|
||||
}
|
||||
let value = timeout.doubleValue
|
||||
if value > 0 && value.rounded(.towardZero) == value && value <= Double(Int.max) {
|
||||
return Int(value)
|
||||
|
||||
@@ -67,4 +67,12 @@ import Testing
|
||||
|
||||
#expect(TalkModeManager.resolvedSilenceTimeoutMs(talk) == 900)
|
||||
}
|
||||
|
||||
@Test func defaultsSilenceTimeoutMsWhenBool() {
|
||||
let talk: [String: Any] = [
|
||||
"silenceTimeoutMs": true,
|
||||
]
|
||||
|
||||
#expect(TalkModeManager.resolvedSilenceTimeoutMs(talk) == 900)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user