Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Examples/ElizaSharedSources/AppSources/MessagingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ struct MessagingView<ViewModel: MessagingViewModel>: View {

HStack {
TextField("Write your message...", text: self.$currentMessage)
.onSubmit(self.sendMessage)
.onSubmit { self.sendMessage() }
.submitLabel(.send)
Button("Send", action: self.sendMessage)
Button("Send", action: { self.sendMessage() })
.foregroundColor(.blue)
}
}
Expand All @@ -82,7 +82,7 @@ struct MessagingView<ViewModel: MessagingViewModel>: View {
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("End Chat") {
self.viewModel.endChat()
Task { await self.viewModel.endChat() }
self.presentationMode.wrappedValue.dismiss()
}
}
Expand Down
22 changes: 11 additions & 11 deletions Examples/ElizaSharedSources/AppSources/MessagingViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,18 @@ protocol MessagingViewModel: ObservableObject {
func send(_ message: String) async

/// End the chat session (and close connections if needed).
func endChat()
func endChat() async
}

/// View model that uses unary requests for messaging.
@MainActor
final class UnaryMessagingViewModel: MessagingViewModel {
private let protocolClient: ProtocolClient
private lazy var elizaClient = Buf_Connect_Demo_Eliza_V1_ElizaServiceClient(
client: self.protocolClient
)

@MainActor @Published private(set) var messages = [Message]()
@Published private(set) var messages = [Message]()

init(protocolOption: ProtocolClientOption) {
self.protocolClient = ProtocolClient(
Expand All @@ -58,32 +59,32 @@ final class UnaryMessagingViewModel: MessagingViewModel {

func send(_ sentence: String) async {
let request = SayRequest.with { $0.sentence = sentence }
await self.addMessage(Message(message: sentence, author: .user))
self.addMessage(Message(message: sentence, author: .user))

let response = await self.elizaClient.say(request: request)
os_log(.debug, "Eliza unary response: %@", String(describing: response))
await self.addMessage(Message(
self.addMessage(Message(
message: response.message?.sentence ?? "No response", author: .eliza
))
}

func endChat() {}
func endChat() async {}

@MainActor
private func addMessage(_ message: Message) {
self.messages.append(message)
}
}

/// View model that uses bidirectional streaming for messaging.
@MainActor
final class BidirectionalStreamingMessagingViewModel: MessagingViewModel {
private let protocolClient: ProtocolClient
private lazy var elizaClient = Buf_Connect_Demo_Eliza_V1_ElizaServiceClient(
client: self.protocolClient
)
private lazy var elizaStream = self.elizaClient.converse()

@MainActor @Published private(set) var messages = [Message]()
@Published private(set) var messages = [Message]()

init(protocolOption: ProtocolClientOption) {
self.protocolClient = ProtocolClient(
Expand All @@ -98,7 +99,7 @@ final class BidirectionalStreamingMessagingViewModel: MessagingViewModel {
func send(_ sentence: String) async {
do {
let request = ConverseRequest.with { $0.sentence = sentence }
await self.addMessage(Message(message: sentence, author: .user))
self.addMessage(Message(message: sentence, author: .user))
try self.elizaStream.send(request)
} catch let error {
os_log(
Expand All @@ -120,7 +121,7 @@ final class BidirectionalStreamingMessagingViewModel: MessagingViewModel {

case .message(let message):
os_log(.debug, "Eliza message: %@", String(describing: message))
await self.addMessage(Message(message: message.sentence, author: .eliza))
self.addMessage(Message(message: message.sentence, author: .eliza))

case .complete(_, let error, let trailers):
os_log(.debug, "Eliza completed with trailers: %@", trailers ?? [:])
Expand All @@ -131,13 +132,12 @@ final class BidirectionalStreamingMessagingViewModel: MessagingViewModel {
} else {
sentence = "[Conversation ended]"
}
await self.addMessage(Message(message: sentence, author: .eliza))
self.addMessage(Message(message: sentence, author: .eliza))
}
}
}
}

@MainActor
private func addMessage(_ message: Message) {
self.messages.append(message)
print(self.messages)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
Expand Down Expand Up @@ -380,6 +381,7 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Connect/Interfaces/Code.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

/// Indicates a status of an RPC.
/// The zero code in gRPC is OK, which indicates that the operation was a success.
public enum Code: Int, CaseIterable, Equatable {
public enum Code: Int, CaseIterable, Equatable, Sendable {
case ok = 0
case canceled = 1
case unknown = 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

/// Structure modeling the final JSON message that is returned by Connect streams:
/// https://connect.build/docs/protocol#error-end-stream
struct ConnectEndStreamResponse {
struct ConnectEndStreamResponse: Sendable {
/// Connect error that was returned with the response.
let error: ConnectError?
/// Additional metadata that was passed with the response. Keys are guaranteed to be lowercased.
Expand Down
4 changes: 2 additions & 2 deletions Libraries/Connect/Interfaces/ConnectError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import SwiftProtobuf

/// Typed error provided by Connect RPCs that may optionally wrap additional typed custom errors
/// using `details`.
public struct ConnectError: Swift.Error {
public struct ConnectError: Swift.Error, Sendable {
/// The resulting status code.
public let code: Code
/// User-readable error message.
Expand Down Expand Up @@ -64,7 +64,7 @@ public struct ConnectError: Swift.Error {
///
/// The `google.golang.org/genproto/googleapis/rpc/errdetails` package contains a
/// variety of Protobuf messages commonly used as error details.
public struct Detail: Swift.Decodable {
public struct Detail: Swift.Decodable, Sendable {
public let type: String
public let payload: Data?

Expand Down
2 changes: 1 addition & 1 deletion Libraries/Connect/Interfaces/HTTPRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import Foundation

/// HTTP request used for sending primitive data to the server.
public struct HTTPRequest {
public struct HTTPRequest: Sendable {
/// Target URL for the request.
public let url: URL
/// Value to assign to the `content-type` header.
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Connect/Interfaces/HTTPResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import Foundation

/// Unary HTTP response received from the server.
public struct HTTPResponse {
public struct HTTPResponse: Sendable {
/// The status code of the response.
public let code: Code
/// Response headers specified by the server.
Expand Down
4 changes: 2 additions & 2 deletions Libraries/Connect/Interfaces/MethodSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

/// Contains metadata for a specific RPC method.
public struct MethodSpec: Equatable, Codable {
public struct MethodSpec: Equatable, Codable, Sendable {
/// The name of the method (1:1 with the `.proto` file). E.g., `Foo`.
public let name: String
/// The fully qualified name of the method's service. E.g., `foo.v1.FooService`.
Expand All @@ -27,7 +27,7 @@ public struct MethodSpec: Equatable, Codable {
return "\(self.service)/\(self.name)"
}

public enum MethodType: Equatable, Codable {
public enum MethodType: Equatable, Codable, Sendable {
case unary
case clientStream
case serverStream
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Connect/Interfaces/ResponseMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import SwiftProtobuf

/// Typed unary response from an RPC.
public struct ResponseMessage<Output: SwiftProtobuf.Message> {
public struct ResponseMessage<Output: SwiftProtobuf.Message & Sendable>: Sendable {
/// The status code of the response.
public let code: Code
/// Response headers specified by the server.
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Connect/Interfaces/Streams/StreamResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
///
/// A typical stream receives `headers > message > message > message ... > complete`.
@frozen
public enum StreamResult<Output> {
public enum StreamResult<Output: Sendable>: Sendable {
/// Stream is complete. Provides the end status code and optionally an error and trailers.
case complete(code: Code, error: Swift.Error?, trailers: Trailers?)
/// Headers have been received over the stream.
Expand Down