@@ -645,6 +645,14 @@ await channel.subscribe((message) => {
645645console.log('Subscriber ready, waiting for tokens...');
646646```
647647
648+ { /* Swift example test harness
649+ ID: anthropic-message-per-response-1
650+ To verify: copy this comment into a Swift file, paste the example code into the function body, run `swift build`
651+
652+ @MainActor
653+ func example_anthropic_message_per_response_1() async throws {
654+ // --- example code starts here ---
655+ */ }
648656``` client_swift
649657import Ably
650658
@@ -657,37 +665,48 @@ let channel = realtime.channels.get("ai:{{RANDOM_CHANNEL_NAME}}")
657665// Track responses by message serial
658666var responses: [String: String] = [:]
659667
660- // Subscribe to receive messages
661- channel.subscribe { message in
662- guard let serial = message.serial else { return }
663-
664- switch message.action {
665- case .create:
666- // New response started
667- print("\n[Response started] \(serial)")
668- responses[serial] = message.data as? String ?? ""
669-
670- case .append:
671- // Append token to existing response
672- let current = responses[serial] ?? ""
673- let token = message.data as? String ?? ""
674- responses[serial] = current + token
675-
676- // Display token as it arrives
677- print(token, terminator: "")
678-
679- case .update:
680- // Replace entire response content
681- responses[serial] = message.data as? String ?? ""
682- print("\n[Response updated with full content]")
683-
684- default:
685- break
686- }
668+ // Subscribe to receive messages and wait for the channel to attach
669+ try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, any Error>) in
670+ channel.subscribe(attachCallback: { error in
671+ if let error {
672+ continuation.resume(throwing: error)
673+ } else {
674+ continuation.resume()
675+ }
676+ }, callback: { message in
677+ MainActor.assumeIsolated {
678+ guard let serial = message.serial else { return }
679+ guard let data = message.data as? String else { return }
680+
681+ switch message.action {
682+ case .create:
683+ // New response started
684+ print("\n[Response started] \(serial)")
685+ responses[serial] = data
686+
687+ case .append:
688+ // Append token to existing response
689+ let current = responses[serial] ?? ""
690+ responses[serial] = current + data
691+
692+ // Display token as it arrives
693+ print(data, terminator: "")
694+
695+ case .update:
696+ // Replace entire response content
697+ responses[serial] = data
698+ print("\n[Response updated with full content]")
699+
700+ default:
701+ break
702+ }
703+ }
704+ })
687705}
688706
689707print("Subscriber ready, waiting for tokens...")
690708```
709+ { /* --- end example code --- */ }
691710
692711``` client_java
693712import io.ably.lib.realtime.AblyRealtime;
@@ -932,6 +951,14 @@ await channel.subscribe((message) => {
932951});
933952```
934953
954+ { /* Swift example test harness
955+ ID: anthropic-message-per-response-2
956+ To verify: copy this comment into a Swift file, paste the example code into the function body, run `swift build`
957+
958+ @MainActor
959+ func example_anthropic_message_per_response_2(realtime: ARTRealtime) async throws {
960+ // --- example code starts here ---
961+ */ }
935962``` client_swift
936963// Use rewind to receive recent historical messages
937964let channelOptions = ARTRealtimeChannelOptions()
@@ -941,29 +968,41 @@ let channel = realtime.channels.get("ai:{{RANDOM_CHANNEL_NAME}}", options: chann
941968
942969var responses: [String: String] = [:]
943970
944- channel.subscribe { message in
945- guard let serial = message.serial else { return }
946-
947- switch message.action {
948- case .create:
949- responses[serial] = message.data as? String ?? ""
950-
951- case .append:
952- let current = responses[serial] ?? ""
953- let token = message.data as? String ?? ""
954- responses[serial] = current + token
955- print(token, terminator: "")
956-
957- case .update:
958- // Historical messages contain full concatenated response
959- responses[serial] = message.data as? String ?? ""
960- print("\n[Historical response]: \(responses[serial] ?? "")")
961-
962- default:
963- break
964- }
971+ // Subscribe and wait for the channel to attach
972+ try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, any Error>) in
973+ channel.subscribe(attachCallback: { error in
974+ if let error {
975+ continuation.resume(throwing: error)
976+ } else {
977+ continuation.resume()
978+ }
979+ }, callback: { message in
980+ MainActor.assumeIsolated {
981+ guard let serial = message.serial else { return }
982+ guard let data = message.data as? String else { return }
983+
984+ switch message.action {
985+ case .create:
986+ responses[serial] = data
987+
988+ case .append:
989+ let current = responses[serial] ?? ""
990+ responses[serial] = current + data
991+ print(data, terminator: "")
992+
993+ case .update:
994+ // Historical messages contain full concatenated response
995+ responses[serial] = data
996+ print("\n[Historical response]: \(responses[serial] ?? "")")
997+
998+ default:
999+ break
1000+ }
1001+ }
1002+ })
9651003}
9661004```
1005+ { /* --- end example code --- */ }
9671006
9681007``` client_java
9691008import io.ably.lib.realtime.AblyRealtime;
0 commit comments