@@ -628,6 +628,14 @@ await channel.subscribe((message) => {
628628console.log('Subscriber ready, waiting for tokens...');
629629```
630630
631+ { /* Swift example test harness
632+ ID: anthropic-message-per-response-1
633+ To verify: copy this comment into a Swift file, paste the example code into the function body, run `swift build`
634+
635+ @MainActor
636+ func example_anthropic_message_per_response_1() async throws {
637+ // --- example code starts here ---
638+ */ }
631639``` client_swift
632640import Ably
633641
@@ -640,37 +648,48 @@ let channel = realtime.channels.get("ai:{{RANDOM_CHANNEL_NAME}}")
640648// Track responses by message serial
641649var responses: [String: String] = [:]
642650
643- // Subscribe to receive messages
644- channel.subscribe { message in
645- guard let serial = message.serial else { return }
646-
647- switch message.action {
648- case .create:
649- // New response started
650- print("\n[Response started] \(serial)")
651- responses[serial] = message.data as? String ?? ""
652-
653- case .messageAppend:
654- // Append token to existing response
655- let current = responses[serial] ?? ""
656- let token = message.data as? String ?? ""
657- responses[serial] = current + token
658-
659- // Display token as it arrives
660- print(token, terminator: "")
661-
662- case .update:
663- // Replace entire response content
664- responses[serial] = message.data as? String ?? ""
665- print("\n[Response updated with full content]")
666-
667- default:
668- break
669- }
651+ // Subscribe to receive messages and wait for the channel to attach
652+ try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, any Error>) in
653+ channel.subscribe(attachCallback: { error in
654+ if let error {
655+ continuation.resume(throwing: error)
656+ } else {
657+ continuation.resume()
658+ }
659+ }, callback: { message in
660+ MainActor.assumeIsolated {
661+ guard let serial = message.serial else { return }
662+ guard let data = message.data as? String else { return }
663+
664+ switch message.action {
665+ case .create:
666+ // New response started
667+ print("\n[Response started] \(serial)")
668+ responses[serial] = data
669+
670+ case .append:
671+ // Append token to existing response
672+ let current = responses[serial] ?? ""
673+ responses[serial] = current + data
674+
675+ // Display token as it arrives
676+ print(data, terminator: "")
677+
678+ case .update:
679+ // Replace entire response content
680+ responses[serial] = data
681+ print("\n[Response updated with full content]")
682+
683+ default:
684+ break
685+ }
686+ }
687+ })
670688}
671689
672690print("Subscriber ready, waiting for tokens...")
673691```
692+ { /* --- end example code --- */ }
674693
675694``` client_java
676695import io.ably.lib.realtime.AblyRealtime;
@@ -909,6 +928,14 @@ await channel.subscribe((message) => {
909928});
910929```
911930
931+ { /* Swift example test harness
932+ ID: anthropic-message-per-response-2
933+ To verify: copy this comment into a Swift file, paste the example code into the function body, run `swift build`
934+
935+ @MainActor
936+ func example_anthropic_message_per_response_2(realtime: ARTRealtime) async throws {
937+ // --- example code starts here ---
938+ */ }
912939``` client_swift
913940// Use rewind to receive recent historical messages
914941let channelOptions = ARTRealtimeChannelOptions()
@@ -918,29 +945,41 @@ let channel = realtime.channels.get("ai:{{RANDOM_CHANNEL_NAME}}", options: chann
918945
919946var responses: [String: String] = [:]
920947
921- channel.subscribe { message in
922- guard let serial = message.serial else { return }
923-
924- switch message.action {
925- case .create:
926- responses[serial] = message.data as? String ?? ""
927-
928- case .messageAppend:
929- let current = responses[serial] ?? ""
930- let token = message.data as? String ?? ""
931- responses[serial] = current + token
932- print(token, terminator: "")
933-
934- case .update:
935- // Historical messages contain full concatenated response
936- responses[serial] = message.data as? String ?? ""
937- print("\n[Historical response]: \(responses[serial] ?? "")")
938-
939- default:
940- break
941- }
948+ // Subscribe and wait for the channel to attach
949+ try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, any Error>) in
950+ channel.subscribe(attachCallback: { error in
951+ if let error {
952+ continuation.resume(throwing: error)
953+ } else {
954+ continuation.resume()
955+ }
956+ }, callback: { message in
957+ MainActor.assumeIsolated {
958+ guard let serial = message.serial else { return }
959+ guard let data = message.data as? String else { return }
960+
961+ switch message.action {
962+ case .create:
963+ responses[serial] = data
964+
965+ case .append:
966+ let current = responses[serial] ?? ""
967+ responses[serial] = current + data
968+ print(data, terminator: "")
969+
970+ case .update:
971+ // Historical messages contain full concatenated response
972+ responses[serial] = data
973+ print("\n[Historical response]: \(responses[serial] ?? "")")
974+
975+ default:
976+ break
977+ }
978+ }
979+ })
942980}
943981```
982+ { /* --- end example code --- */ }
944983
945984``` client_java
946985import io.ably.lib.realtime.AblyRealtime;
0 commit comments