Skip to content

Commit b4c8950

Browse files
committed
refactor: centralize talk silence timeout defaults
1 parent 4e2290b commit b4c8950

File tree

14 files changed

+89
-24
lines changed

14 files changed

+89
-24
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package ai.openclaw.app.voice
2+
3+
internal object TalkDefaults {
4+
const val defaultSilenceTimeoutMs = 700L
5+
}

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ class TalkModeManager(
6060
private const val defaultModelIdFallback = "eleven_v3"
6161
private const val defaultOutputFormatFallback = "pcm_24000"
6262
private const val defaultTalkProvider = "elevenlabs"
63-
private const val defaultSilenceTimeoutMs = 700L
6463
private const val listenWatchdogMs = 12_000L
6564
private const val chatFinalWaitWithSubscribeMs = 45_000L
6665
private const val chatFinalWaitWithoutSubscribeMs = 6_000L
@@ -118,11 +117,12 @@ class TalkModeManager(
118117
}
119118

120119
internal fun resolvedSilenceTimeoutMs(talk: JsonObject?): Long {
121-
val primitive = talk?.get("silenceTimeoutMs") as? JsonPrimitive ?: return defaultSilenceTimeoutMs
122-
if (primitive.isString) return defaultSilenceTimeoutMs
123-
val timeout = primitive.content.toDoubleOrNull() ?: return defaultSilenceTimeoutMs
120+
val fallback = TalkDefaults.defaultSilenceTimeoutMs
121+
val primitive = talk?.get("silenceTimeoutMs") as? JsonPrimitive ?: return fallback
122+
if (primitive.isString) return fallback
123+
val timeout = primitive.content.toDoubleOrNull() ?: return fallback
124124
if (timeout <= 0 || timeout % 1.0 != 0.0 || timeout > Long.MAX_VALUE.toDouble()) {
125-
return defaultSilenceTimeoutMs
125+
return fallback
126126
}
127127
return timeout.toLong()
128128
}
@@ -155,7 +155,7 @@ class TalkModeManager(
155155
private var listeningMode = false
156156

157157
private var silenceJob: Job? = null
158-
private var silenceWindowMs = defaultSilenceTimeoutMs
158+
private var silenceWindowMs = TalkDefaults.defaultSilenceTimeoutMs
159159
private var lastTranscript: String = ""
160160
private var lastHeardAtMs: Long? = null
161161
private var lastSpokenText: String? = null
@@ -1467,7 +1467,7 @@ class TalkModeManager(
14671467
}
14681468
configLoaded = true
14691469
} catch (_: Throwable) {
1470-
silenceWindowMs = defaultSilenceTimeoutMs
1470+
silenceWindowMs = TalkDefaults.defaultSilenceTimeoutMs
14711471
defaultVoiceId = envVoice?.takeIf { it.isNotEmpty() } ?: sagVoice?.takeIf { it.isNotEmpty() }
14721472
defaultModelId = defaultModelIdFallback
14731473
if (!modelOverrideActive) currentModelId = defaultModelId

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,20 +94,20 @@ class TalkModeConfigParsingTest {
9494

9595
@Test
9696
fun defaultsSilenceTimeoutMsWhenMissing() {
97-
assertEquals(700L, TalkModeManager.resolvedSilenceTimeoutMs(null))
97+
assertEquals(TalkDefaults.defaultSilenceTimeoutMs, TalkModeManager.resolvedSilenceTimeoutMs(null))
9898
}
9999

100100
@Test
101101
fun defaultsSilenceTimeoutMsWhenInvalid() {
102102
val talk = buildJsonObject { put("silenceTimeoutMs", 0) }
103103

104-
assertEquals(700L, TalkModeManager.resolvedSilenceTimeoutMs(talk))
104+
assertEquals(TalkDefaults.defaultSilenceTimeoutMs, TalkModeManager.resolvedSilenceTimeoutMs(talk))
105105
}
106106

107107
@Test
108108
fun defaultsSilenceTimeoutMsWhenString() {
109109
val talk = buildJsonObject { put("silenceTimeoutMs", "1500") }
110110

111-
assertEquals(700L, TalkModeManager.resolvedSilenceTimeoutMs(talk))
111+
assertEquals(TalkDefaults.defaultSilenceTimeoutMs, TalkModeManager.resolvedSilenceTimeoutMs(talk))
112112
}
113113
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
enum TalkDefaults {
2+
static let silenceTimeoutMs = 900
3+
}

apps/ios/Sources/Voice/TalkModeManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ final class TalkModeManager: NSObject {
3434
private typealias SpeechRequest = SFSpeechAudioBufferRecognitionRequest
3535
private static let defaultModelIdFallback = "eleven_v3"
3636
private static let defaultTalkProvider = "elevenlabs"
37-
private static let defaultSilenceTimeoutMs = 900
37+
private static let defaultSilenceTimeoutMs = TalkDefaults.silenceTimeoutMs
3838
private static let redactedConfigSentinel = "__OPENCLAW_REDACTED__"
3939
var isEnabled: Bool = false
4040
var isListening: Bool = false

apps/ios/Tests/TalkModeConfigParsingTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,22 @@ import Testing
6060
}
6161

6262
@Test func defaultsSilenceTimeoutMsWhenMissing() {
63-
#expect(TalkModeManager.resolvedSilenceTimeoutMs(nil) == 900)
63+
#expect(TalkModeManager.resolvedSilenceTimeoutMs(nil) == TalkDefaults.silenceTimeoutMs)
6464
}
6565

6666
@Test func defaultsSilenceTimeoutMsWhenInvalid() {
6767
let talk: [String: Any] = [
6868
"silenceTimeoutMs": 0,
6969
]
7070

71-
#expect(TalkModeManager.resolvedSilenceTimeoutMs(TalkConfigParsing.bridgeFoundationDictionary(talk)) == 900)
71+
#expect(TalkModeManager.resolvedSilenceTimeoutMs(TalkConfigParsing.bridgeFoundationDictionary(talk)) == TalkDefaults.silenceTimeoutMs)
7272
}
7373

7474
@Test func defaultsSilenceTimeoutMsWhenBool() {
7575
let talk: [String: Any] = [
7676
"silenceTimeoutMs": true,
7777
]
7878

79-
#expect(TalkModeManager.resolvedSilenceTimeoutMs(TalkConfigParsing.bridgeFoundationDictionary(talk)) == 900)
79+
#expect(TalkModeManager.resolvedSilenceTimeoutMs(TalkConfigParsing.bridgeFoundationDictionary(talk)) == TalkDefaults.silenceTimeoutMs)
8080
}
8181
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
enum TalkDefaults {
2+
static let silenceTimeoutMs = 700
3+
}

apps/macos/Sources/OpenClaw/TalkModeRuntime.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ actor TalkModeRuntime {
1212
private let ttsLogger = Logger(subsystem: "ai.openclaw", category: "talk.tts")
1313
private static let defaultModelIdFallback = "eleven_v3"
1414
private static let defaultTalkProvider = "elevenlabs"
15-
private static let defaultSilenceTimeoutMs = 700
15+
private static let defaultSilenceTimeoutMs = TalkDefaults.silenceTimeoutMs
1616

1717
private final class RMSMeter: @unchecked Sendable {
1818
private let lock = NSLock()

apps/macos/Tests/OpenClawIPCTests/TalkModeConfigParsingTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,23 +33,23 @@ struct TalkModeConfigParsingTests {
3333
#expect(selection?.config["apiKey"]?.stringValue == "legacy-key")
3434
}
3535

36-
@Test func readsConfiguredSilenceTimeoutMs() {
36+
@Test func `reads configured silence timeout ms`() {
3737
let talk: [String: AnyCodable] = [
3838
"silenceTimeoutMs": AnyCodable(1500),
3939
]
4040

4141
#expect(TalkModeRuntime.resolvedSilenceTimeoutMs(talk) == 1500)
4242
}
4343

44-
@Test func defaultsSilenceTimeoutMsWhenMissing() {
45-
#expect(TalkModeRuntime.resolvedSilenceTimeoutMs(nil) == 700)
44+
@Test func `defaults silence timeout ms when missing`() {
45+
#expect(TalkModeRuntime.resolvedSilenceTimeoutMs(nil) == TalkDefaults.silenceTimeoutMs)
4646
}
4747

48-
@Test func defaultsSilenceTimeoutMsWhenInvalid() {
48+
@Test func `defaults silence timeout ms when invalid`() {
4949
let talk: [String: AnyCodable] = [
5050
"silenceTimeoutMs": AnyCodable(0),
5151
]
5252

53-
#expect(TalkModeRuntime.resolvedSilenceTimeoutMs(talk) == 700)
53+
#expect(TalkModeRuntime.resolvedSilenceTimeoutMs(talk) == TalkDefaults.silenceTimeoutMs)
5454
}
5555
}

docs/gateway/configuration-reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,7 @@ Defaults for Talk mode (macOS/iOS/Android).
16691669
- `apiKey` and `providers.*.apiKey` accept plaintext strings or SecretRef objects.
16701670
- `ELEVENLABS_API_KEY` fallback applies only when no Talk API key is configured.
16711671
- `voiceAliases` lets Talk directives use friendly names.
1672-
- `silenceTimeoutMs` controls how long Talk mode waits after user silence before it sends the transcript. Unset keeps the platform default pause window (`700` ms on macOS and Android, `900` ms on iOS).
1672+
- `silenceTimeoutMs` controls how long Talk mode waits after user silence before it sends the transcript. Unset keeps the platform default pause window (`700 ms on macOS and Android, 900 ms on iOS`).
16731673

16741674
---
16751675

0 commit comments

Comments
 (0)