This commit is contained in:
@@ -183,6 +183,29 @@ actor SybilAPIClient: SybilAPIClienting {
|
||||
SybilLog.info(SybilLog.network, "Chat stream completed")
|
||||
}
|
||||
|
||||
func runQuickQuestionStream(
|
||||
body: QuickQuestionStreamRequest,
|
||||
onEvent: @escaping @Sendable (CompletionStreamEvent) async -> Void
|
||||
) async throws {
|
||||
let request = try makeRequest(
|
||||
path: "/v1/quick-questions/stream",
|
||||
method: "POST",
|
||||
body: AnyEncodable(body),
|
||||
acceptsSSE: true
|
||||
)
|
||||
|
||||
SybilLog.info(
|
||||
SybilLog.network,
|
||||
"Starting quick question stream POST \(request.url?.absoluteString ?? "<unknown>")"
|
||||
)
|
||||
|
||||
try await stream(request: request) { eventName, dataText in
|
||||
try await Self.handleCompletionStreamEvent(eventName: eventName, dataText: dataText, onEvent: onEvent)
|
||||
}
|
||||
|
||||
SybilLog.info(SybilLog.network, "Quick question stream completed")
|
||||
}
|
||||
|
||||
func attachCompletionStream(
|
||||
chatID: String,
|
||||
onEvent: @escaping @Sendable (CompletionStreamEvent) async -> Void
|
||||
@@ -664,6 +687,12 @@ struct CompletionStreamRequest: Codable, Sendable {
|
||||
var userLocation: String? = nil
|
||||
}
|
||||
|
||||
struct QuickQuestionStreamRequest: Codable, Sendable {
|
||||
var provider: Provider
|
||||
var model: String
|
||||
var question: String
|
||||
}
|
||||
|
||||
private struct ChatCreateBody: Encodable {
|
||||
var title: String?
|
||||
var provider: Provider?
|
||||
|
||||
@@ -27,6 +27,10 @@ protocol SybilAPIClienting: Sendable {
|
||||
body: CompletionStreamRequest,
|
||||
onEvent: @escaping @Sendable (CompletionStreamEvent) async -> Void
|
||||
) async throws
|
||||
func runQuickQuestionStream(
|
||||
body: QuickQuestionStreamRequest,
|
||||
onEvent: @escaping @Sendable (CompletionStreamEvent) async -> Void
|
||||
) async throws
|
||||
func attachCompletionStream(
|
||||
chatID: String,
|
||||
onEvent: @escaping @Sendable (CompletionStreamEvent) async -> Void
|
||||
|
||||
@@ -1162,13 +1162,11 @@ final class SybilViewModel {
|
||||
let streamStatus = CompletionStreamStatus()
|
||||
|
||||
do {
|
||||
try await client().runCompletionStream(
|
||||
body: CompletionStreamRequest(
|
||||
chatId: nil,
|
||||
persist: false,
|
||||
try await client().runQuickQuestionStream(
|
||||
body: QuickQuestionStreamRequest(
|
||||
provider: provider,
|
||||
model: model,
|
||||
messages: [CompletionRequestMessage(role: .user, content: prompt)]
|
||||
question: prompt
|
||||
)
|
||||
) { [weak self] event in
|
||||
guard let self else { return }
|
||||
|
||||
@@ -22,6 +22,7 @@ private struct MockClientCallSnapshot: Sendable {
|
||||
var getSearch = 0
|
||||
var getActiveRuns = 0
|
||||
var runCompletionStream = 0
|
||||
var runQuickQuestionStream = 0
|
||||
var attachCompletionStream = 0
|
||||
var attachSearchStream = 0
|
||||
}
|
||||
@@ -50,7 +51,7 @@ private actor MockSybilClient: SybilAPIClienting {
|
||||
|
||||
private var snapshot = MockClientCallSnapshot()
|
||||
private var lastCreateChatCall: ChatCreateCallSnapshot?
|
||||
private var lastCompletionStreamBody: CompletionStreamRequest?
|
||||
private var lastQuickQuestionStreamBody: QuickQuestionStreamRequest?
|
||||
private var completionStreamEvents: [CompletionStreamEvent]?
|
||||
private var listChatsDelayNanoseconds: UInt64 = 0
|
||||
private var listSearchesDelayNanoseconds: UInt64 = 0
|
||||
@@ -103,8 +104,8 @@ private actor MockSybilClient: SybilAPIClienting {
|
||||
lastCreateChatCall
|
||||
}
|
||||
|
||||
func currentCompletionStreamBody() -> CompletionStreamRequest? {
|
||||
lastCompletionStreamBody
|
||||
func currentQuickQuestionStreamBody() -> QuickQuestionStreamRequest? {
|
||||
lastQuickQuestionStreamBody
|
||||
}
|
||||
|
||||
func setCompletionStreamEvents(_ events: [CompletionStreamEvent], delayNanoseconds: UInt64 = 0) {
|
||||
@@ -287,7 +288,27 @@ private actor MockSybilClient: SybilAPIClienting {
|
||||
onEvent: @escaping @Sendable (CompletionStreamEvent) async -> Void
|
||||
) async throws {
|
||||
snapshot.runCompletionStream += 1
|
||||
lastCompletionStreamBody = body
|
||||
if completionStreamDelayNanoseconds > 0 {
|
||||
try await Task.sleep(nanoseconds: completionStreamDelayNanoseconds)
|
||||
}
|
||||
if let completionStreamNetworkErrorMessage {
|
||||
throw APIError.networkError(message: completionStreamNetworkErrorMessage)
|
||||
}
|
||||
if let completionStreamEvents {
|
||||
for event in completionStreamEvents {
|
||||
await onEvent(event)
|
||||
}
|
||||
return
|
||||
}
|
||||
throw UnexpectedClientCall()
|
||||
}
|
||||
|
||||
func runQuickQuestionStream(
|
||||
body: QuickQuestionStreamRequest,
|
||||
onEvent: @escaping @Sendable (CompletionStreamEvent) async -> Void
|
||||
) async throws {
|
||||
snapshot.runQuickQuestionStream += 1
|
||||
lastQuickQuestionStreamBody = body
|
||||
if completionStreamDelayNanoseconds > 0 {
|
||||
try await Task.sleep(nanoseconds: completionStreamDelayNanoseconds)
|
||||
}
|
||||
@@ -1005,7 +1026,8 @@ private func makeToolCallMessage(id: String, date: Date, summary: String = "Ran
|
||||
await first?.value
|
||||
|
||||
let calls = await client.currentSnapshot()
|
||||
#expect(calls.runCompletionStream == 1)
|
||||
#expect(calls.runQuickQuestionStream == 1)
|
||||
#expect(calls.runCompletionStream == 0)
|
||||
#expect(viewModel.quickQuestionAnswerText == "One answer.")
|
||||
#expect(!viewModel.isQuickQuestionSending)
|
||||
}
|
||||
@@ -1021,12 +1043,12 @@ private func makeToolCallMessage(id: String, date: Date, summary: String = "Ran
|
||||
await task?.value
|
||||
|
||||
let calls = await client.currentSnapshot()
|
||||
#expect(calls.runCompletionStream == 0)
|
||||
#expect(calls.runQuickQuestionStream == 0)
|
||||
#expect(!viewModel.isQuickQuestionSending)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
@Test func quickQuestionRunsNonPersistentCompletionStream() async throws {
|
||||
@Test func quickQuestionUsesDedicatedServerEndpoint() async throws {
|
||||
let client = MockSybilClient()
|
||||
await client.setCompletionStreamEvents([
|
||||
.delta(CompletionStreamDelta(text: "Reset it from ")),
|
||||
@@ -1041,13 +1063,11 @@ private func makeToolCallMessage(id: String, date: Date, summary: String = "Ran
|
||||
await task?.value
|
||||
|
||||
let snapshot = await client.currentSnapshot()
|
||||
let body = await client.currentCompletionStreamBody()
|
||||
#expect(snapshot.runCompletionStream == 1)
|
||||
#expect(body?.persist == false)
|
||||
#expect(body?.chatId == nil)
|
||||
let body = await client.currentQuickQuestionStreamBody()
|
||||
#expect(snapshot.runQuickQuestionStream == 1)
|
||||
#expect(snapshot.runCompletionStream == 0)
|
||||
#expect(body?.provider == .openai)
|
||||
#expect(body?.messages.first?.role == .user)
|
||||
#expect(body?.messages.first?.content == "How do I reset my password?")
|
||||
#expect(body?.question == "How do I reset my password?")
|
||||
#expect(viewModel.quickQuestionAnswerText == "Reset it from Settings.")
|
||||
#expect(!viewModel.isQuickQuestionSending)
|
||||
}
|
||||
@@ -1572,7 +1592,7 @@ private final class MockQuickQuestionLifecycle {
|
||||
#expect(panel.state.prompt == "Keep this draft")
|
||||
#expect(panel.state.answer == "An answer arrived while hidden.")
|
||||
let calls = await client.currentSnapshot()
|
||||
#expect(calls.runCompletionStream == 0)
|
||||
#expect(calls.runQuickQuestionStream == 0)
|
||||
controller.stop()
|
||||
}
|
||||
|
||||
@@ -1630,7 +1650,7 @@ private final class MockQuickQuestionLifecycle {
|
||||
#expect(panel.presentationCount == 2)
|
||||
#expect(panel.state.canSend)
|
||||
let calls = await client.currentSnapshot()
|
||||
#expect(calls.runCompletionStream == 0)
|
||||
#expect(calls.runQuickQuestionStream == 0)
|
||||
controller.stop()
|
||||
}
|
||||
|
||||
@@ -1652,7 +1672,7 @@ private final class MockQuickQuestionLifecycle {
|
||||
#expect(panel.state.prompt == "A signed-out question")
|
||||
#expect(!viewModel.isQuickQuestionSending)
|
||||
let calls = await client.currentSnapshot()
|
||||
#expect(calls.runCompletionStream == 0)
|
||||
#expect(calls.runQuickQuestionStream == 0)
|
||||
controller.stop()
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user