From f49cf1a43ae444bf13795e91b8a288dca46b03c6 Mon Sep 17 00:00:00 2001 From: zak Date: Wed, 6 May 2026 13:53:21 +0100 Subject: [PATCH 1/2] Amend AIT-ST1/CT1 for client + channelName API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the `createAgentSession` (AIT-ST1) and `createClientSession` (AIT-CT1) factory specs to reflect the new option shape: an `Ably.Realtime` client and a `channelName` instead of a pre-resolved `Ably.RealtimeChannel`. The session resolves the channel internally via `client.channels.get(channelName)`. Add sub-points AIT-ST1a and AIT-CT1a covering agent registration: on construction, both sessions must register the `ai-transport-js` identifier with the SDK version on the Realtime client's `options.agents` map for usage tracking. Registration is idempotent across sessions sharing a client. Specify that `close()` does not release the channel or close the client — the caller owns the client lifecycle. --- specifications/ai-transport-features.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specifications/ai-transport-features.md b/specifications/ai-transport-features.md index 596a76b14..6b6e8885c 100644 --- a/specifications/ai-transport-features.md +++ b/specifications/ai-transport-features.md @@ -77,7 +77,8 @@ The agent (server-side) session manages the run lifecycle over an Ably channel. ### Factory -- `(AIT-ST1)` The SDK must provide a `createAgentSession` factory that accepts a channel, codec, optional logger, and optional `onError` callback, and returns an `AgentSession`. +- `(AIT-ST1)` The SDK must provide a `createAgentSession` factory that accepts an `Ably.Realtime` client, a channel name, a codec, an optional logger, and an optional `onError` callback, and returns an `AgentSession`. + - `(AIT-ST1a)` On construction the agent session must call `client.channels.get(channelName)` to resolve the channel, and must register the `ai-transport-js` agent identifier with the SDK version on the Realtime client's `options.agents` map for usage tracking. Registration must be idempotent — repeated calls with the same client must produce the same key/value, so multiple sessions sharing one client are safe. The session must not close the client or release the channel on `close()`; the caller owns the client's lifecycle. - `(AIT-ST2)` `connect()` must subscribe to the cancel message name (`x-ably-cancel`) on the channel — subscribe implicitly attaches the channel — so that cancel messages from clients are routed to active runs. It must be idempotent: subsequent calls return the same promise. All run-lifecycle methods (`start`, `addMessages`, `addEvents`, `pipe`, `end`) must throw `InvalidArgument` until `connect()` resolves. ### Run Lifecycle @@ -132,7 +133,8 @@ The client session manages the client-side conversation lifecycle over an Ably c ### Factory -- `(AIT-CT1)` The SDK must provide a `createClientSession` factory that accepts a channel, codec, and session options, and returns a `ClientSession`. +- `(AIT-CT1)` The SDK must provide a `createClientSession` factory that accepts an `Ably.Realtime` client, a channel name, a codec, and session options, and returns a `ClientSession`. + - `(AIT-CT1a)` On construction the client session must call `client.channels.get(channelName)` to resolve the channel, and must register the `ai-transport-js` agent identifier with the SDK version on the Realtime client's `options.agents` map for usage tracking. Registration must be idempotent — repeated calls with the same client must produce the same key/value, so multiple sessions sharing one client are safe. The session must not close the client or release the channel on `close()`; the caller owns the client's lifecycle. - `(AIT-CT2)` `connect()` must subscribe to the channel for incoming messages — subscribe implicitly attaches the channel (Ably RTL7g) to guarantee no messages are missed. It must be idempotent: subsequent calls return the same promise. All write methods (`send`, `regenerate`, `edit`, `update`, `cancel`, `waitForRun`) must throw `InvalidArgument` until `connect()` resolves. ### Send From 277f8f82beb5a6fbaa5214ff2995ee9b13f1c087 Mon Sep 17 00:00:00 2001 From: zak Date: Fri, 8 May 2026 15:13:53 +0100 Subject: [PATCH 2/2] Rewrite AIT-ST1a/CT1a as a fallback chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the single agents-map sentence on AIT-ST1a / AIT-CT1a with three sub-items modeled on chat spec CHA-IN1: - 1a1: where the underlying Realtime SDK exposes a wrapper-SDK proxy (createWrapperSDKProxy, per CHA-IN1a), use it. - 1a2: where it does not (current ably-js), inject options.agents AND pass params.agent on channels.get — what AIT-JS does today. Mirrors CHA-IN1e. - 1a3: agent identifiers must be registered in ably-common/protocol/agents.json per RSC7d5. Writing the requirement as a fallback chain keeps the spec forward- compatible with the eventual ADR-117 wrapper-SDK proxy work in ably-js without a future spec rewrite, and gives the upcoming Swift/Kotlin AIT SDKs (which target ably-cocoa/ably-java where the proxy already exists) the right primary path to reach for. The top-level points also gain an ownership clause: the session owns its channel, so callers must not resolve the same channel name elsewhere with conflicting options. --- specifications/ai-transport-features.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/specifications/ai-transport-features.md b/specifications/ai-transport-features.md index 6b6e8885c..9814cad91 100644 --- a/specifications/ai-transport-features.md +++ b/specifications/ai-transport-features.md @@ -78,7 +78,10 @@ The agent (server-side) session manages the run lifecycle over an Ably channel. ### Factory - `(AIT-ST1)` The SDK must provide a `createAgentSession` factory that accepts an `Ably.Realtime` client, a channel name, a codec, an optional logger, and an optional `onError` callback, and returns an `AgentSession`. - - `(AIT-ST1a)` On construction the agent session must call `client.channels.get(channelName)` to resolve the channel, and must register the `ai-transport-js` agent identifier with the SDK version on the Realtime client's `options.agents` map for usage tracking. Registration must be idempotent — repeated calls with the same client must produce the same key/value, so multiple sessions sharing one client are safe. The session must not close the client or release the channel on `close()`; the caller owns the client's lifecycle. + - `(AIT-ST1a)` On construction the agent session must configure the supplied Realtime client to attribute usage to this SDK and resolve the channel by name. Configuration must be idempotent — repeated construction with the same client must leave the attribution state unchanged, so multiple sessions sharing one client are safe. The session must not close the client or release the channel on `close()`; the caller owns the client's lifecycle. The session owns its channel — callers must not also resolve the same channel name elsewhere with conflicting channel options. The attribution mechanism follows the fallback chain in `AIT-ST1a1`–`AIT-ST1a3`, modeled on chat spec [CHA-IN1](https://sdk.ably.com/builds/ably/specification/main/chat-features/#CHA-IN1). + - `(AIT-ST1a1)` Where the underlying Realtime SDK exposes a wrapper-SDK proxy mechanism (per [CHA-IN1a](https://sdk.ably.com/builds/ably/specification/main/chat-features/#CHA-IN1a)), the session must use it with `{ agents: { 'ai-transport-js': VERSION } }` and use the proxy for all subsequent channel operations. + - `(AIT-ST1a2)` Where the wrapper-SDK proxy mechanism does not exist (current ably-js), the session must inject `'ai-transport-js' -> VERSION` into the client's `options.agents` map AND pass `{ params: { agent: 'ai-transport-js/' } }` on `client.channels.get(channelName)`. Mirrors [CHA-IN1e](https://sdk.ably.com/builds/ably/specification/main/chat-features/#CHA-IN1e). + - `(AIT-ST1a3)` SDK authors must register the agent identifiers used here in the common repository (`ably-common/protocol/agents.json`), per [RSC7d5](https://sdk.ably.com/builds/ably/specification/main/features/#RSC7d5). - `(AIT-ST2)` `connect()` must subscribe to the cancel message name (`x-ably-cancel`) on the channel — subscribe implicitly attaches the channel — so that cancel messages from clients are routed to active runs. It must be idempotent: subsequent calls return the same promise. All run-lifecycle methods (`start`, `addMessages`, `addEvents`, `pipe`, `end`) must throw `InvalidArgument` until `connect()` resolves. ### Run Lifecycle @@ -134,7 +137,10 @@ The client session manages the client-side conversation lifecycle over an Ably c ### Factory - `(AIT-CT1)` The SDK must provide a `createClientSession` factory that accepts an `Ably.Realtime` client, a channel name, a codec, and session options, and returns a `ClientSession`. - - `(AIT-CT1a)` On construction the client session must call `client.channels.get(channelName)` to resolve the channel, and must register the `ai-transport-js` agent identifier with the SDK version on the Realtime client's `options.agents` map for usage tracking. Registration must be idempotent — repeated calls with the same client must produce the same key/value, so multiple sessions sharing one client are safe. The session must not close the client or release the channel on `close()`; the caller owns the client's lifecycle. + - `(AIT-CT1a)` On construction the client session must configure the supplied Realtime client to attribute usage to this SDK and resolve the channel by name. Configuration must be idempotent — repeated construction with the same client must leave the attribution state unchanged, so multiple sessions sharing one client are safe. The session must not close the client or release the channel on `close()`; the caller owns the client's lifecycle. The session owns its channel — callers must not also resolve the same channel name elsewhere with conflicting channel options. The attribution mechanism follows the fallback chain in `AIT-CT1a1`–`AIT-CT1a3`, modeled on chat spec [CHA-IN1](https://sdk.ably.com/builds/ably/specification/main/chat-features/#CHA-IN1). + - `(AIT-CT1a1)` Where the underlying Realtime SDK exposes a wrapper-SDK proxy mechanism (per [CHA-IN1a](https://sdk.ably.com/builds/ably/specification/main/chat-features/#CHA-IN1a)), the session must use it with `{ agents: { 'ai-transport-js': VERSION } }` and use the proxy for all subsequent channel operations. + - `(AIT-CT1a2)` Where the wrapper-SDK proxy mechanism does not exist (current ably-js), the session must inject `'ai-transport-js' -> VERSION` into the client's `options.agents` map AND pass `{ params: { agent: 'ai-transport-js/' } }` on `client.channels.get(channelName)`. Mirrors [CHA-IN1e](https://sdk.ably.com/builds/ably/specification/main/chat-features/#CHA-IN1e). + - `(AIT-CT1a3)` SDK authors must register the agent identifiers used here in the common repository (`ably-common/protocol/agents.json`), per [RSC7d5](https://sdk.ably.com/builds/ably/specification/main/features/#RSC7d5). - `(AIT-CT2)` `connect()` must subscribe to the channel for incoming messages — subscribe implicitly attaches the channel (Ably RTL7g) to guarantee no messages are missed. It must be idempotent: subsequent calls return the same promise. All write methods (`send`, `regenerate`, `edit`, `update`, `cancel`, `waitForRun`) must throw `InvalidArgument` until `connect()` resolves. ### Send