# How durable sessions unify human-to-human and human-to-agent messages

> Source: <https://ably.com/blog/durable-sessions-human-ai-collaboration>
> Published: 2026-06-26 11:05:55+00:00

AI chats are often a rather solitary experience: just you and ChatGPT, sitting there together, solving a problem. But so many of the tasks that we perform day to day are ones that benefit from, or often even require, collaboration with other people such as colleagues, family members, or friends.

So, if AI agents are helpful, and other people are helpful, then how can we provide a space for multiple people to collaborate with each other *and* with AI agents?

This is a question to which the flagship AI chat products don’t yet have a good answer: the best you can do in ChatGPT or Claude is to share your chat with somebody else, for them to fork and continue the conversation independently.

That said, it’s encouraging to see that the companies behind these products are starting to think about this problem. For example, Anthropic’s recently-launched [Claude Design](https://www.anthropic.com/news/claude-design-anthropic-labs) offers one approach: whilst a design still has a single owner who drives the chat with Claude, the tool provides a separate “Comments” section in which you can invite team members to discuss the design. Perhaps your colleague thinks that this button should be bigger and more yellow; another colleague disagrees, thinking it should be rounder and orangey. You have some back-and-forth and eventually decide to make it rounder but keep the colour the same. Once you’ve decided this, you can press a “Resolve with Claude” button on the comment thread which submits its contents to Claude, who then updates the design in response.

In this article, we’ll explore a different model: a single chat in which agents and multiple people are all equal, first-class collaborators. We’ll take a look at a demo that allows you and your friends to plan a day out together with the help of an AI assistant who you can involve in your conversation precisely at the moments when you want his help. Then we’ll explain how [durable sessions](https://durablesessions.ai/) are a primitive that provide a shared space for agents and humans to exchange messages and for humans to invoke agents when needed, and how [Ably AI Transport](https://ably.com/ai-transport) provides a simple, extensible implementation of this primitive.

## Demo: planning a day out with friends

### Making initial plans

Alice and Steve are friends who are chatting with each other through a messaging app, planning a day out. They exchange a few messages, agreeing on an area to meet and a few things to do.

So far, this is just a normal chat between two people; no AI here. But now, Steve tags Bernard, our helpful AI assistant, to do the hard work of actually finding the places to go and planning the day out.

Bernard leaps into action, choosing places to go and updating a shared itinerary. Alice and Steve both see Bernard’s responses streaming in realtime.

### Some more back-and-forth

Once Bernard has done his work, the conversation goes back to being a normal chat; he won’t get involved until Alice or Steve tag him again.

Alice and Steve then chat some more, discussing some changes that they'd like to make to the itinerary.

They agree on their plans and once again summon Bernard, who has full visibility of the new messages that Alice and Steve exchanged. Bernard researches places to go based on these new preferences and updates the itinerary.

### New participants

Later on, their friend Trevor joins the chat. When he opens the chat, he sees all of the conversation history and also the shared itinerary. He tags Bernard to ask him what’s been planned so far, and Bernard fills him in on the plans.

Trevor can now also get involved in collaborating on the plans, just like Alice and Steve were doing before.

### Video

Take a look at this video, which shows it all in action:

## Durable sessions: a shared medium for everyone

Most client-side AI frameworks only concern themselves with how a single user exchanges messages with AI agents. When the user sends a message from the chat UI, this unconditionally performs an HTTP request that submits the message history to the agent for processing. All of the session state is stored locally in the client-side app. There is no concept of interacting with other users.

A *durable session* provides an addressable medium that is shared between agents and humans. It stores all of the conversation state for a given chat, and syncs this state between all participants (human and AI) in the chat. Submitting a message to a durable session does not automatically trigger AI inference; rather, the session provides a separate mechanism for your app to trigger this inference when appropriate for the UX that you are building. Once invoked, the agent can use all of the messages that have been exchanged so far to decide its next move.

Because the conversation lives in the session rather than in any single client, a durable session is inherently multi-user: several people share one conversation. It is also multi-agent: you can bring more than one agent into the same session, each appearing as just another participant.

### Choosing when the agent does work

That split between sending a message and invoking an agent is worth dwelling on, because it’s the part that’s hard to get any other way. In a typical client-side setup, such as the [Vercel AI SDK](https://ai-sdk.dev/)’s `useChat`

, sending a message *is* the agent call: the client holds the conversation locally and POSTs the whole history to the agent on every send, so the agent runs every single time. There is no shared place for a message to live that isn’t also a request for inference, so plain human-to-human messages have nowhere to go without bolting on a second channel and reconciling it yourself.

With a durable session the two are separate operations. In the demo, the client always publishes a message into the session, and only invokes Bernard when someone actually tags him:

```
// Client (browser)

// Publish the message into the shared session, where everyone sees it.
const run = await view.send(UIMessageCodec.createUserMessage(userMessage(text)));

// Waking Bernard is a separate step, taken only when he's mentioned.
if (mentionsBernard(text)) {
  await fetch('/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(run.toInvocation().toJSON()),
  });
}
```

When Bernard is invoked, he rebuilds the conversation from the session itself, so he sees everything Alice and Steve said while he was sitting out. On the server, the agent endpoint turns that invocation into a run, reconstructs the conversation, and streams the reply back over the session:

```
// Server (agent endpoint at /api/chat)

// The invocation is just a pointer; the conversation lives on the channel.
const invocation = Invocation.fromJSON(await req.json());
const session = createAgentSession({ client: ably, channelName: invocation.sessionName });
await session.connect();
const run = session.createRun(invocation);

await run.start();
await run.loadConversation(); // rebuild the whole conversation from the session

const result = streamText({
  model: anthropic('claude-sonnet-4-6'),
  messages: await convertToModelMessages(run.messages),
  tools,
});

// Stream the reply back over the session, where every participant sees it.
await run.pipe(result.toUIMessageStream());
```

### Catching up when you join late

A late joiner catches up automatically, for the same reason: the conversation lives in the session, not in any one client. When Trevor opened the chat earlier, the SDK replayed the full history (every message from Alice, Steve, and Bernard) and the shared itinerary straight from the session, with no special “load history” call to the server. The same mechanism covers a page refresh, a dropped connection, or picking the conversation up on a second device.

## Ably AI Transport SDK: Durable sessions in practice

At Ably, we believe that durable sessions will allow developers to build the next generation of agentic applications. We’ve built the [Ably AI Transport SDK](https://github.com/ably/ably-ai-transport-js), which provides an implementation of durable sessions on top of [Ably channels](https://ably.com/docs/channels). The demo we showed above was built using it.

On the React side, there are two ways in. If you’re already using Vercel’s `useChat`

, the SDK ships a drop-in transport: you keep the hook and just swap in ours. This demo goes a little deeper and uses the SDK’s own React hooks instead (the `view.send`

above comes from one of them, `useView`

), because it needs the explicit control over when Bernard is invoked that we covered above. Either way you don’t have to build the realtime or state layer yourself: those hooks are the same shape as `useChat`

, handing you a synced `messages`

list and a `send`

, so you write your own message components and little else.

On the server, the change is small: your inference code stays the same, since the agent is still a normal Vercel `streamText`

call. You just wrap that call in an AI Transport session, as the snippet above shows.

When you use Ably AI Transport, you also get access to all of the features that come built in with Ably channels. For example, in the demo, we used [Ably LiveObjects](https://ably.com/liveobjects) to drive the shared itinerary: the agent writes itinerary updates to a shared LiveMap, and clients receive updates to the itinerary in realtime, using these updates to drive the itinerary UI (the map and the list).

In addition to the features that we’ve shown in this demo, Ably AI Transport also offers you:

**Resumable streaming** that survives reconnections and the corporate proxies that quietly kill long-lived HTTP streams.**Session continuity across devices**, with three delivery paths from one SDK: stream while connected, catch up on reconnect, and push notification when offline.**Agent presence**, so a crashed or stalled agent is a presence event rather than something you infer from a silent stream.** Human handover**, where a person can step into a live session and take over from an agent without the conversation breaking.** Bidirectional control**, so a user can cancel, redirect, or steer an agent mid-run instead of cancelling and starting over.** Multi-agent coordination**, with several agents fanning into a single session.

Try it yourself – build a multi-user AI session with Ably AI Transport. [Get started with the docs →](https://ably.com/docs/ai-transport)
