fix(ios): start incremental speech at soft boundaries (#33305)

Merged via squash.

Prepared head SHA: d1acf72317
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
This commit is contained in:
Mariano
2026-03-03 22:36:40 +00:00
committed by GitHub
parent 22e33ddda9
commit a36ccf4156
3 changed files with 38 additions and 2 deletions

View File

@@ -1682,6 +1682,8 @@ final class TalkModeManager: NSObject {
}
private struct IncrementalSpeechBuffer {
private static let softBoundaryMinChars = 72
private(set) var latestText: String = ""
private(set) var directive: TalkDirective?
private var spokenOffset: Int = 0
@@ -1774,8 +1776,9 @@ private struct IncrementalSpeechBuffer {
}
if !inCodeBlock {
buffer.append(chars[idx])
if Self.isBoundary(chars[idx]) {
let currentChar = chars[idx]
buffer.append(currentChar)
if Self.isBoundary(currentChar) || Self.isSoftBoundary(currentChar, bufferedChars: buffer.count) {
lastBoundary = idx + 1
bufferAtBoundary = buffer
inCodeBlockAtBoundary = inCodeBlock
@@ -1802,6 +1805,10 @@ private struct IncrementalSpeechBuffer {
private static func isBoundary(_ ch: Character) -> Bool {
ch == "." || ch == "!" || ch == "?" || ch == "\n"
}
private static func isSoftBoundary(_ ch: Character, bufferedChars: Int) -> Bool {
bufferedChars >= Self.softBoundaryMinChars && ch.isWhitespace
}
}
extension TalkModeManager {

View File

@@ -0,0 +1,28 @@
import Testing
@testable import OpenClaw
@MainActor
@Suite struct TalkModeIncrementalSpeechBufferTests {
@Test func emitsSoftBoundaryBeforeTerminalPunctuation() {
let manager = TalkModeManager(allowSimulatorCapture: true)
manager._test_incrementalReset()
let partial =
"We start speaking earlier by splitting this long stream chunk at a whitespace boundary before punctuation arrives"
let segments = manager._test_incrementalIngest(partial, isFinal: false)
#expect(segments.count == 1)
#expect(segments[0].count >= 72)
#expect(segments[0].count < partial.count)
}
@Test func keepsShortChunkBufferedWithoutPunctuation() {
let manager = TalkModeManager(allowSimulatorCapture: true)
manager._test_incrementalReset()
let short = "short chunk without punctuation"
let segments = manager._test_incrementalIngest(short, isFinal: false)
#expect(segments.isEmpty)
}
}