feat(keyboard): ship AI mode surface with streaming search answers

Add the AI keyboard tab, Agent settings, and user-owned LLM key path for 1.7.0, including streaming answers and web-search transports without the built-in DeepSeek fallback.
This commit is contained in:
Rocky
2026-08-11 01:06:27 +08:00
parent f6212dcd2c
commit 3de665d254
81 changed files with 4467 additions and 398 deletions
@@ -285,6 +285,42 @@ final class FlowSessionBridgeTests: XCTestCase {
XCTAssertNil(reencoded["previousOutput"])
}
func testAIQuestionCommandRoundTripPreservesConversationIdentity() throws {
let conversationID = UUID()
let command = FlowCommand(
sessionId: UUID(),
utteranceId: UUID(),
commandSeq: 46,
action: .startRecording,
localeId: "zh-Hans",
utteranceMode: .aiQuestion,
aiConversationID: conversationID
)
let decoded = try JSONDecoder().decode(
FlowCommand.self,
from: JSONEncoder().encode(command)
)
XCTAssertEqual(decoded.resolvedUtteranceMode, .aiQuestion)
XCTAssertEqual(decoded.aiConversationID, conversationID)
}
func testAIQuestionResultNeverAllowsRawASRFallback() {
let result = FlowResult(
sessionId: UUID(),
utteranceId: UUID(),
commandSeq: 47,
status: .rawReady,
text: "原始问题",
rawText: "原始问题",
utteranceMode: .aiQuestion,
aiConversationID: UUID()
)
XCTAssertFalse(result.allowsRawFallback)
}
func testFlowResultRoundTripPreservesUtteranceIdentity() {
let defaults = makeDefaults()
let sessionId = UUID()