# Adaptor and decoder Internal adaptor and decoder components: the pipe writer that streams and repairs appends, and delivery through the codec. An [agent adaptor](https://ably.com/docs/ai-transport/api/javascript/agent-adaptor.md) is one channel and one codec, and a [decoder](https://ably.com/docs/ai-transport/api/javascript/decoder.md) reads the messages of the same codec. These are the parts inside them, and how they coordinate the codec, the channel and your application code. ## Pipe writer `pipe()` reads a source of events one at a time, encodes each one, and gives the messages to a pipe writer. The writer keeps a key table for the life of the pipe. A codec names streams by its own keys, such as a message id or a tool call id, because it cannot know the serial Ably returns for a publish: - `publish` under a key publishes the message and remembers its serial. - `append` to a key that is not live publishes the message, waits for its serial and remembers it, so a stream's first delta opens the message. `append` to a live key appends. - `update` replaces the content of the message under a live key, and `ends` forgets a key. The writer sends appends without waiting for them, so a response streams at the speed of the connection rather than one round trip per token. It waits for a stream's pending appends before it sends the message that ends the stream. Ably rolls up the appends a connection publishes within a short window into one delivery, and the wait keeps the end message from being delivered ahead of the stream's last text. If an append fails, the writer carries on. When the stream ends, it repairs the message with one update that carries the full content, before the end message. History then holds the whole message, and a live client reads the missing text as the update's new part. If the repair fails, the pipe rejects with `PipeFailed`. On every exit, cancellation included, the pipe flushes and repairs what it wrote and releases the source before it settles, so a cancelled pipe leaves whole messages on the channel. ## Delivery Your application typically subscribes the decoder with `channel.subscribe(decoder.receive)`, which adds the listener and then attaches the channel, so no message can arrive before something receives it. Every inbound message goes through the codec: - Each event the codec decodes becomes one delivery, with the event and the Ably message. - A message the codec has nothing for, such as another publisher's message, a message the codec has already seen, or a deleted message, becomes one delivery with `event` set to `undefined`. - A message whose decode throws becomes one delivery with `event` set to `undefined`, and the error goes to the decoder's `onError` handlers as `SessionMessageProcessingFailed`. The application always sees the raw message and decides what to do with it. Every handler receives every delivery. A handler that throws is logged, and the other handlers still receive the delivery. ## History replay Your application can read history itself and pass each message to `decoder.decode`, which returns the deliveries without emitting them. Use the same decoder for history and live messages, so a message that both carry decodes once while its stream is open. History pages arrive newest first, and the decoder does not reorder deliveries. To receive history and live messages in order from one subscription, your application can [rewind](https://ably.com/docs/channels/options/rewind.md) the channel to a serial stored in your database. ## Channel continuity The adaptor and the decoder do not watch the channel's state. Your application should watch the channel's state to detect a loss of continuity, and then [recover the conversation](https://ably.com/docs/ai-transport/conversation/reconnection-and-recovery.md#recover). The handler still receives the full text of a stream in flight during the gap. The first message Ably delivers after the channel attaches again carries the full content so far, and the decoder core passes on only the part the handler has not received. ## Close A pipe stops when the signal passed to [`pipe()`](https://ably.com/docs/ai-transport/api/javascript/agent-adaptor.md#pipe) fires, and flushes and repairs what it wrote before it rejects with `OperationCancelled`. To stop reading, your application can call `channel.unsubscribe(decoder.receive)`. The Ably client stays connected, because your application owns it. ## Related pages - [Wire protocol](https://ably.com/docs/ai-transport/internals/wire-protocol.md): the fields the adaptor writes on the channel. - [Codec architecture](https://ably.com/docs/ai-transport/internals/codec-architecture.md): how the decoder core reads appends, updates and history. - [Agent adaptor](https://ably.com/docs/ai-transport/api/javascript/agent-adaptor.md) and [decoder](https://ably.com/docs/ai-transport/api/javascript/decoder.md) API references: the methods these parts sit behind. ## Related Topics - [Overview](https://ably.com/docs/ai-transport/internals.md): The internal architecture of Ably AI Transport. Wire protocol, codec architecture, and the adaptor and decoder. - [Wire protocol](https://ably.com/docs/ai-transport/internals/wire-protocol.md): The Ably channel wire format used by AI Transport: the extras.ai fields a codec and the adaptor write, streamed and plain messages, and call headers. - [Codec architecture](https://ably.com/docs/ai-transport/internals/codec-architecture.md): How an AI Transport codec translates events to Ably messages and back, how defineCodec builds one from an event table, and how the decoder core handles appends, updates and history. ## Documentation Index To discover additional Ably documentation: 1. Fetch [llms.txt](https://ably.com/llms.txt) for the canonical list of available pages. 2. Identify relevant URLs from that index. 3. Fetch target pages as needed. Avoid using assumed or outdated documentation paths.