refactor: centralize talk silence timeout defaults

This commit is contained in:
Peter Steinberger
2026-03-08 14:52:12 +00:00
parent 4e2290b841
commit b4c8950417
14 changed files with 89 additions and 24 deletions

View File

@@ -0,0 +1,5 @@
package ai.openclaw.app.voice
internal object TalkDefaults {
const val defaultSilenceTimeoutMs = 700L
}

View File

@@ -60,7 +60,6 @@ class TalkModeManager(
private const val defaultModelIdFallback = "eleven_v3"
private const val defaultOutputFormatFallback = "pcm_24000"
private const val defaultTalkProvider = "elevenlabs"
private const val defaultSilenceTimeoutMs = 700L
private const val listenWatchdogMs = 12_000L
private const val chatFinalWaitWithSubscribeMs = 45_000L
private const val chatFinalWaitWithoutSubscribeMs = 6_000L
@@ -118,11 +117,12 @@ class TalkModeManager(
}
internal fun resolvedSilenceTimeoutMs(talk: JsonObject?): Long {
val primitive = talk?.get("silenceTimeoutMs") as? JsonPrimitive ?: return defaultSilenceTimeoutMs
if (primitive.isString) return defaultSilenceTimeoutMs
val timeout = primitive.content.toDoubleOrNull() ?: return defaultSilenceTimeoutMs
val fallback = TalkDefaults.defaultSilenceTimeoutMs
val primitive = talk?.get("silenceTimeoutMs") as? JsonPrimitive ?: return fallback
if (primitive.isString) return fallback
val timeout = primitive.content.toDoubleOrNull() ?: return fallback
if (timeout <= 0 || timeout % 1.0 != 0.0 || timeout > Long.MAX_VALUE.toDouble()) {
return defaultSilenceTimeoutMs
return fallback
}
return timeout.toLong()
}
@@ -155,7 +155,7 @@ class TalkModeManager(
private var listeningMode = false
private var silenceJob: Job? = null
private var silenceWindowMs = defaultSilenceTimeoutMs
private var silenceWindowMs = TalkDefaults.defaultSilenceTimeoutMs
private var lastTranscript: String = ""
private var lastHeardAtMs: Long? = null
private var lastSpokenText: String? = null
@@ -1467,7 +1467,7 @@ class TalkModeManager(
}
configLoaded = true
} catch (_: Throwable) {
silenceWindowMs = defaultSilenceTimeoutMs
silenceWindowMs = TalkDefaults.defaultSilenceTimeoutMs
defaultVoiceId = envVoice?.takeIf { it.isNotEmpty() } ?: sagVoice?.takeIf { it.isNotEmpty() }
defaultModelId = defaultModelIdFallback
if (!modelOverrideActive) currentModelId = defaultModelId

View File

@@ -94,20 +94,20 @@ class TalkModeConfigParsingTest {
@Test
fun defaultsSilenceTimeoutMsWhenMissing() {
assertEquals(700L, TalkModeManager.resolvedSilenceTimeoutMs(null))
assertEquals(TalkDefaults.defaultSilenceTimeoutMs, TalkModeManager.resolvedSilenceTimeoutMs(null))
}
@Test
fun defaultsSilenceTimeoutMsWhenInvalid() {
val talk = buildJsonObject { put("silenceTimeoutMs", 0) }
assertEquals(700L, TalkModeManager.resolvedSilenceTimeoutMs(talk))
assertEquals(TalkDefaults.defaultSilenceTimeoutMs, TalkModeManager.resolvedSilenceTimeoutMs(talk))
}
@Test
fun defaultsSilenceTimeoutMsWhenString() {
val talk = buildJsonObject { put("silenceTimeoutMs", "1500") }
assertEquals(700L, TalkModeManager.resolvedSilenceTimeoutMs(talk))
assertEquals(TalkDefaults.defaultSilenceTimeoutMs, TalkModeManager.resolvedSilenceTimeoutMs(talk))
}
}

View File

@@ -0,0 +1,3 @@
enum TalkDefaults {
static let silenceTimeoutMs = 900
}

View File

@@ -34,7 +34,7 @@ final class TalkModeManager: NSObject {
private typealias SpeechRequest = SFSpeechAudioBufferRecognitionRequest
private static let defaultModelIdFallback = "eleven_v3"
private static let defaultTalkProvider = "elevenlabs"
private static let defaultSilenceTimeoutMs = 900
private static let defaultSilenceTimeoutMs = TalkDefaults.silenceTimeoutMs
private static let redactedConfigSentinel = "__OPENCLAW_REDACTED__"
var isEnabled: Bool = false
var isListening: Bool = false

View File

@@ -60,7 +60,7 @@ import Testing
}
@Test func defaultsSilenceTimeoutMsWhenMissing() {
#expect(TalkModeManager.resolvedSilenceTimeoutMs(nil) == 900)
#expect(TalkModeManager.resolvedSilenceTimeoutMs(nil) == TalkDefaults.silenceTimeoutMs)
}
@Test func defaultsSilenceTimeoutMsWhenInvalid() {
@@ -68,7 +68,7 @@ import Testing
"silenceTimeoutMs": 0,
]
#expect(TalkModeManager.resolvedSilenceTimeoutMs(TalkConfigParsing.bridgeFoundationDictionary(talk)) == 900)
#expect(TalkModeManager.resolvedSilenceTimeoutMs(TalkConfigParsing.bridgeFoundationDictionary(talk)) == TalkDefaults.silenceTimeoutMs)
}
@Test func defaultsSilenceTimeoutMsWhenBool() {
@@ -76,6 +76,6 @@ import Testing
"silenceTimeoutMs": true,
]
#expect(TalkModeManager.resolvedSilenceTimeoutMs(TalkConfigParsing.bridgeFoundationDictionary(talk)) == 900)
#expect(TalkModeManager.resolvedSilenceTimeoutMs(TalkConfigParsing.bridgeFoundationDictionary(talk)) == TalkDefaults.silenceTimeoutMs)
}
}

View File

@@ -0,0 +1,3 @@
enum TalkDefaults {
static let silenceTimeoutMs = 700
}

View File

@@ -12,7 +12,7 @@ actor TalkModeRuntime {
private let ttsLogger = Logger(subsystem: "ai.openclaw", category: "talk.tts")
private static let defaultModelIdFallback = "eleven_v3"
private static let defaultTalkProvider = "elevenlabs"
private static let defaultSilenceTimeoutMs = 700
private static let defaultSilenceTimeoutMs = TalkDefaults.silenceTimeoutMs
private final class RMSMeter: @unchecked Sendable {
private let lock = NSLock()

View File

@@ -33,7 +33,7 @@ struct TalkModeConfigParsingTests {
#expect(selection?.config["apiKey"]?.stringValue == "legacy-key")
}
@Test func readsConfiguredSilenceTimeoutMs() {
@Test func `reads configured silence timeout ms`() {
let talk: [String: AnyCodable] = [
"silenceTimeoutMs": AnyCodable(1500),
]
@@ -41,15 +41,15 @@ struct TalkModeConfigParsingTests {
#expect(TalkModeRuntime.resolvedSilenceTimeoutMs(talk) == 1500)
}
@Test func defaultsSilenceTimeoutMsWhenMissing() {
#expect(TalkModeRuntime.resolvedSilenceTimeoutMs(nil) == 700)
@Test func `defaults silence timeout ms when missing`() {
#expect(TalkModeRuntime.resolvedSilenceTimeoutMs(nil) == TalkDefaults.silenceTimeoutMs)
}
@Test func defaultsSilenceTimeoutMsWhenInvalid() {
@Test func `defaults silence timeout ms when invalid`() {
let talk: [String: AnyCodable] = [
"silenceTimeoutMs": AnyCodable(0),
]
#expect(TalkModeRuntime.resolvedSilenceTimeoutMs(talk) == 700)
#expect(TalkModeRuntime.resolvedSilenceTimeoutMs(talk) == TalkDefaults.silenceTimeoutMs)
}
}