Wire protocol

Wire-format detail for AI Transport over Ably channels: the fields AI Transport writes on each message, and how a streamed response is laid out on the channel.

AI Transport writes ordinary Ably messages to the conversation's Ably channel. Any Ably client can read them, and the fields below are what AI Transport puts on them. The codec owns a message's name, data and most of its extras. The transport adds a small number of fields of its own.

Extras fields

Ably accepts only known keys at the top level of a message's extras. AI Transport uses two:

KeyWritten byContents
extras.aiThe codec builder and the transportThe SDK's own fields. Ably reserves this key for AI Transport, and a value under it travels as it is, nested objects included.
extras.headersThe codec and the callerFlat headers, which Ably's server-side filtering reads. Values must be strings, numbers, booleans or null.

Under extras.ai, a codec built with defineCodec writes two fields, and the transport writes two more:

FieldWritten byMeaning
typeCodec builderThe event type, which picks the codec row on decode.
fieldsCodec builderThe row's event fields that travel beside data, nested values included.
streamTransporttrue on every write under a live stream key: the publish that opens the stream, each append, and each update.
endsTransportOn the message that ends a stream, the serial of the stream's message.

A codec written by hand can put its own fields anywhere Ably allows. The transport's two fields are the only ones it writes under extras.ai.

Call headers

send() and pipe() take headers, which the transport adds under extras.headers on every message the call publishes. A codec row can write headers there too. Where both set a key, the row's value is used. A subscriber reads the merged map from delivery.message.extras.headers.

The codecs that ship with the SDK write no headers of their own, so extras.headers holds only the call's headers. A common use is a requestId that ties a response to the prompt it answers.

Plain and streamed messages

A codec row says where each message goes:

  • A plain publish has no key. It is one Ably message that nothing appends to.
  • A streamed message is opened under a key. The pipe publishes it for the stream's first delta, remembers its serial under the key, and appends each later delta's data to it. Ably concatenates appended data, so the message's data is the stream's text so far.
  • The message that ends a stream is published after the stream's appends have been acknowledged, with extras.ai.ends set to the serial of the stream's message.

Ably replaces a message's name and extras with those of the latest append. That is why a stream's first delta opens the message, rather than a separate start event: history then holds the start event, one message with the stream's whole text under the delta's type, and the end event, which decode the same way as the live sequence.

Read a streamed message back

A streamed message reaches a client in one of three ways:

How it arrivesdataVersion
A live appendThe appended fragment.Each append has a new version.serial.
The first delivery after an attachThe full content so far, as a message.update.The message's latest version.serial.
A history readThe whole message at its latest version.The message's latest version.serial.

The decoder core uses the message serial to identify the stream, and the version.serial to tell which deliveries it has already seen. fromSerial compares the message serial when it replays history, even for a message that was appended to later.

Channel options

The transport sets the channel's options when it creates the channel:

  • params.agent carries the SDK's attribution, including the codec's adapterTag.
  • The channel modes are the default channel modes, plus any channelModes the application requested, such as OBJECT_MODES.
  • echo follows the transport's echoMessages option, which defaults to true.

Ask for the channel by name with no options, ably.channels.get(channelName), to reuse it for presence or LiveObjects. Passing options of your own would replace the ones the transport set.