Skip to content
Draft
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
135 changes: 87 additions & 48 deletions src/pages/docs/guides/ai-transport/anthropic-message-per-response.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,14 @@ await channel.subscribe((message) => {
console.log('Subscriber ready, waiting for tokens...');
```

{/* Swift example test harness
ID: anthropic-message-per-response-1
To verify: copy this comment into a Swift file, paste the example code into the function body, run `swift build`

@MainActor
func example_anthropic_message_per_response_1() async throws {
// --- example code starts here ---
*/}
```client_swift
import Ably

Expand All @@ -640,37 +648,48 @@ let channel = realtime.channels.get("ai:{{RANDOM_CHANNEL_NAME}}")
// Track responses by message serial
var responses: [String: String] = [:]

// Subscribe to receive messages
channel.subscribe { message in
guard let serial = message.serial else { return }

switch message.action {
case .create:
// New response started
print("\n[Response started] \(serial)")
responses[serial] = message.data as? String ?? ""

case .messageAppend:
// Append token to existing response
let current = responses[serial] ?? ""
let token = message.data as? String ?? ""
responses[serial] = current + token

// Display token as it arrives
print(token, terminator: "")

case .update:
// Replace entire response content
responses[serial] = message.data as? String ?? ""
print("\n[Response updated with full content]")

default:
break
}
// Subscribe to receive messages and wait for the channel to attach
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, any Error>) in
channel.subscribe(attachCallback: { error in
if let error {
continuation.resume(throwing: error)
} else {
continuation.resume()
}
}, callback: { message in
MainActor.assumeIsolated {
guard let serial = message.serial else { return }
guard let data = message.data as? String else { return }

switch message.action {
case .create:
// New response started
print("\n[Response started] \(serial)")
responses[serial] = data

case .append:
// Append token to existing response
let current = responses[serial] ?? ""
responses[serial] = current + data

// Display token as it arrives
print(data, terminator: "")

case .update:
// Replace entire response content
responses[serial] = data
print("\n[Response updated with full content]")

default:
break
}
}
})
}

print("Subscriber ready, waiting for tokens...")
```
{/* --- end example code --- */}

```client_java
import io.ably.lib.realtime.AblyRealtime;
Expand Down Expand Up @@ -909,6 +928,14 @@ await channel.subscribe((message) => {
});
```

{/* Swift example test harness
ID: anthropic-message-per-response-2
To verify: copy this comment into a Swift file, paste the example code into the function body, run `swift build`

@MainActor
func example_anthropic_message_per_response_2(realtime: ARTRealtime) async throws {
// --- example code starts here ---
*/}
```client_swift
// Use rewind to receive recent historical messages
let channelOptions = ARTRealtimeChannelOptions()
Expand All @@ -918,29 +945,41 @@ let channel = realtime.channels.get("ai:{{RANDOM_CHANNEL_NAME}}", options: chann

var responses: [String: String] = [:]

channel.subscribe { message in
guard let serial = message.serial else { return }

switch message.action {
case .create:
responses[serial] = message.data as? String ?? ""

case .messageAppend:
let current = responses[serial] ?? ""
let token = message.data as? String ?? ""
responses[serial] = current + token
print(token, terminator: "")

case .update:
// Historical messages contain full concatenated response
responses[serial] = message.data as? String ?? ""
print("\n[Historical response]: \(responses[serial] ?? "")")

default:
break
}
// Subscribe and wait for the channel to attach
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, any Error>) in
channel.subscribe(attachCallback: { error in
if let error {
continuation.resume(throwing: error)
} else {
continuation.resume()
}
}, callback: { message in
MainActor.assumeIsolated {
guard let serial = message.serial else { return }
guard let data = message.data as? String else { return }

switch message.action {
case .create:
responses[serial] = data

case .append:
let current = responses[serial] ?? ""
responses[serial] = current + data
print(data, terminator: "")

case .update:
// Historical messages contain full concatenated response
responses[serial] = data
print("\n[Historical response]: \(responses[serial] ?? "")")

default:
break
}
}
})
}
```
{/* --- end example code --- */}

```client_java
import io.ably.lib.realtime.AblyRealtime;
Expand Down
74 changes: 50 additions & 24 deletions src/pages/docs/guides/ai-transport/anthropic-message-per-token.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,14 @@ await channel.subscribe('stop', (message) => {
console.log('Subscriber ready, waiting for tokens...');
```

{/* Swift example test harness
ID: anthropic-message-per-token-1
To verify: copy this comment into a Swift file, paste the example code into the function body, run `swift build`

@MainActor
func example_anthropic_message_per_token_1() async throws {
// --- example code starts here ---
*/}
```client_swift
import Ably

Expand All @@ -625,34 +633,52 @@ let channel = realtime.channels.get("{{RANDOM_CHANNEL_NAME}}")
// Track responses by ID
var responses: [String: String] = [:]

// Handle response start
channel.subscribe("start") { message in
guard let responseId = message.extras?.headers?["responseId"] as? String else { return }
print("\n[Response started] \(responseId)")
responses[responseId] = ""
}

// Handle tokens
channel.subscribe("token") { message in
guard let responseId = message.extras?.headers?["responseId"] as? String,
let token = message.data as? String else { return }

// Append token to response
responses[responseId, default: ""] += token

// Display token as it arrives
print(token, terminator: "")
}

// Handle response stop
channel.subscribe("stop") { message in
guard let responseId = message.extras?.headers?["responseId"] as? String else { return }
let finalText = responses[responseId] ?? ""
print("\n[Response completed] \(responseId)")
// Subscribe to all events and handle by message name
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, any Error>) in
channel.subscribe(attachCallback: { error in
if let error {
continuation.resume(throwing: error)
} else {
continuation.resume()
}
}) { message in
MainActor.assumeIsolated {
guard let extras = (try? message.extras?.toJSON()) as? [String: Any],
let headers = extras["headers"] as? [String: Any],
let responseID = headers["responseId"] as? String else { return }

switch message.name {
case "start":
// Handle response start
print("\n[Response started] \(responseID)")
responses[responseID] = ""

case "token":
// Handle tokens
guard let token = message.data as? String else { return }

// Append token to response
let currentText = responses[responseID] ?? ""
responses[responseID] = currentText + token

// Display token as it arrives
print(token, terminator: "")

case "stop":
// Handle response stop
let finalText = responses[responseID]
print("\n[Response completed] \(responseID)")

default:
break
}
}
}
}

print("Subscriber ready, waiting for tokens...")
```
{/* --- end example code --- */}

```client_java
import io.ably.lib.realtime.AblyRealtime;
Expand Down