fix(talk): harden TTS + add system fallback

This commit is contained in:
Peter Steinberger
2025-12-30 07:40:02 +01:00
parent a7617e4d79
commit f86772f26c
22 changed files with 839 additions and 468 deletions

View File

@@ -0,0 +1,20 @@
import XCTest
@testable import ClawdisKit
final class ElevenLabsTTSValidationTests: XCTestCase {
func testValidatedOutputFormatAllowsOnlyMp3Presets() {
XCTAssertEqual(ElevenLabsTTSClient.validatedOutputFormat("mp3_44100_128"), "mp3_44100_128")
XCTAssertNil(ElevenLabsTTSClient.validatedOutputFormat("pcm_16000"))
}
func testValidatedLanguageAcceptsTwoLetterCodes() {
XCTAssertEqual(ElevenLabsTTSClient.validatedLanguage("EN"), "en")
XCTAssertNil(ElevenLabsTTSClient.validatedLanguage("eng"))
}
func testValidatedNormalizeAcceptsKnownValues() {
XCTAssertEqual(ElevenLabsTTSClient.validatedNormalize("AUTO"), "auto")
XCTAssertNil(ElevenLabsTTSClient.validatedNormalize("maybe"))
}
}

View File

@@ -50,6 +50,18 @@ final class TalkDirectiveTests: XCTestCase {
XCTAssertEqual(result.stripped, "Hello.")
}
func testSkipsLeadingEmptyLinesWhenParsingDirective() {
let text = """
{"voice":"abc123"}
Hello there.
"""
let result = TalkDirectiveParser.parse(text)
XCTAssertEqual(result.directive?.voiceId, "abc123")
XCTAssertEqual(result.stripped, "Hello there.")
}
func testTracksUnknownKeys() {
let text = """
{"voice":"abc","mystery":"value","extra":1}

View File

@@ -0,0 +1,16 @@
import XCTest
@testable import ClawdisKit
final class TalkHistoryTimestampTests: XCTestCase {
func testSecondsTimestampsAreAcceptedWithSmallTolerance() {
XCTAssertTrue(TalkHistoryTimestamp.isAfter(999.6, sinceSeconds: 1000))
XCTAssertFalse(TalkHistoryTimestamp.isAfter(999.4, sinceSeconds: 1000))
}
func testMillisecondsTimestampsAreAcceptedWithSmallTolerance() {
let sinceSeconds = 1_700_000_000.0
let sinceMs = sinceSeconds * 1000
XCTAssertTrue(TalkHistoryTimestamp.isAfter(sinceMs - 500, sinceSeconds: sinceSeconds))
XCTAssertFalse(TalkHistoryTimestamp.isAfter(sinceMs - 501, sinceSeconds: sinceSeconds))
}
}

View File

@@ -0,0 +1,16 @@
import XCTest
@testable import ClawdisKit
final class TalkPromptBuilderTests: XCTestCase {
func testBuildIncludesTranscript() {
let prompt = TalkPromptBuilder.build(transcript: "Hello", interruptedAtSeconds: nil)
XCTAssertTrue(prompt.contains("Talk Mode active."))
XCTAssertTrue(prompt.hasSuffix("\n\nHello"))
}
func testBuildIncludesInterruptionLineWhenProvided() {
let prompt = TalkPromptBuilder.build(transcript: "Hi", interruptedAtSeconds: 1.234)
XCTAssertTrue(prompt.contains("Assistant speech interrupted at 1.2s."))
}
}

View File

@@ -0,0 +1,24 @@
import XCTest
@testable import ClawdisKit
final class TalkTTSValidationTests: XCTestCase {
func testResolveSpeedUsesRateWPMWhenProvided() {
let resolved = TalkTTSValidation.resolveSpeed(speed: nil, rateWPM: 175)
XCTAssertNotNil(resolved)
XCTAssertEqual(resolved ?? 0, 1.0, accuracy: 0.0001)
XCTAssertNil(TalkTTSValidation.resolveSpeed(speed: nil, rateWPM: 400))
}
func testValidatedUnitBounds() {
XCTAssertEqual(TalkTTSValidation.validatedUnit(0), 0)
XCTAssertEqual(TalkTTSValidation.validatedUnit(1), 1)
XCTAssertNil(TalkTTSValidation.validatedUnit(-0.01))
XCTAssertNil(TalkTTSValidation.validatedUnit(1.01))
}
func testValidatedSeedBounds() {
XCTAssertEqual(TalkTTSValidation.validatedSeed(0), 0)
XCTAssertEqual(TalkTTSValidation.validatedSeed(1234), 1234)
XCTAssertNil(TalkTTSValidation.validatedSeed(-1))
}
}