Agentic apps that go beyond chat Ably and Vercel released Wayfarer, an open-source demo of a collaborative AI travel-planning app that uses a durable session to synchronize real-time agent streams, shared state, and multi-user presence without custom infrastructure. The app replaces the standard Vercel AI SDK transport with Ably's, enabling live updates, agent tool calls, and user interactions to persist across devices and participants. This approach solves the complexity of building real-time, collaborative AI applications beyond simple chat interfaces. You are planning a trip with an AI assistant on your laptop. You are chatting with the agent, and as you progress it is dropping pins on a map, building a day-by-day itinerary, adding up a budget, and streaming its reasoning as it goes. The state of your interactive session is a combination of the chat history, the synthetic UI constructed by the agent during that process, and structured state, the itinerary, arising from the decisions you each make. Building such an app has challenges beyond getting the agent and LLM to work effectively. You want the experience to be realtime and interactive: both the user and the agent can send a message or modify the shared state at any time. Those changes need to be persisted, as well as disseminated to everyone in realtime. Persisting shared trip state by itself isn’t difficult; the trip is structured data in a database behind an API, the way web apps have stored and served state since REST APIs took hold in the mid-2000s. What is hard is making it live and collaborative: a streaming agent, shared state, and several participants have to stay coherent across refreshes, devices, and people joining and leaving. Done by hand, that means stitching a realtime layer, a stream store, a state-sync system, and presence onto that stored data, and operating all of it. Wayfarer https://github.com/ably-labs/vercel-build-ai-travel-guide is a working demo of exactly that, and it is a standard Vercel AI SDK app: useChat , a model, the chat UI you would write for any LLM chat app. Its transport instead points at Ably, and that one change moves the work onto a durable session. The agent's stream, the shared plan, and the people in the trip are each a property of that one addressable session, so the app attaches to it instead of building delivery, state sync, and awareness on its own. Try it live https://vercel-build-ai-travel-guide.vercel.app/ , or read on to see how it works. Key takeaways - Collaborative AI apps are not just about text responses to text prompts. Beyond a minimal chat experience, even if driven by chat, apps can have complex control flow steering, cancellation , structured state that both agent and user collaborate on, and presence. - A durable session makes this possible by handling persisted state, and the realtime events that mutate it, in a unified way. A durable session is addressable and outlives any connection, device, or participant, so the stream, the shared state, and presence stay in one place. - Ably AI Transport drops into the Vercel AI SDK as a custom transport, so you keep your chat UI and model and build no stream store, sync layer, or presence service. What makes a collaborative AI app hard to build Start from the app you would actually ship. The trip already lives in a database, keyed by id, with an API to read and update it. That is an ordinary stateful service. On top of that, the demands stack up: - Several people open the same trip, and each one needs to see the others' changes as they happen. - The AI agent is a participant too. It streams its reasoning token by token, and at the same time it edits the shared plan by calling tools. - A user has to be able to stop the agent mid-run, and the stop has to reach it and actually halt the work, not just close a connection that leaves it running. - Every surface, each person's tab, their phone, a friend's laptop, has to stay in sync through refreshes, reconnections, and people joining and leaving. To deliver that, you assemble several systems. You add a realtime layer to fanout changes out to every client. You add a way to stream the agent's tokens to all of those clients, not just the one that made the request, and to resume a stream that drops mid-response. In practice, that means a buffer such as Redis, plus endpoints that track and replay the active stream. The Vercel AI SDK's own resumable streams guide https://ai-sdk.dev/docs/ai-sdk-ui/chatbot-resume-streams walks through exactly that build. You add presence to show who is here. You add a back-channel so a user can stop the agent, because a one-way stream cannot carry that signal. Keeping all of it consistent is where it gets genuinely hard. The agent's tokens and its edits to the plan have to arrive in order, on every screen, and survive a reconnect without duplicating or dropping anything. Getting that right was difficult well before AI agents, and it is much of why realtime platforms exist. An agent that streams while it rewrites the same state only makes the ordering harder to guarantee. A better model will not fix this. It lives in the layer between the agent and the user https://ably.com/blog/ai-agent-model-is-fine-but-the-session-is-broken , and most teams build and operate it themselves, piece by piece. One durable session instead of a stitched-together stack Wayfarer skips that stack. It runs the trip on one durable session on Ably, and attaches to it instead of building the pieces. The session even persists while no one is connected, so a traveler can step away and pick the trip up later, with any stops a friend added while they were away. The agent runs Anthropic's Claude Sonnet 4.6, and its logic is the same as in any other Vercel AI SDK app. What changes is the transport underneath it. The Vercel AI SDK was designed for this. useChat accepts a pluggable ChatTransport https://ai-sdk.dev/docs/ai-sdk-ui/transport custom-transport-configuration , so a different transport can take over delivery while the SDK keeps rendering the stream and managing UI state. Ably AI Transport is a custom transport https://ably.com/blog/custom-transport-vercel-ai-sdk that drops into that slot. On the client, the only real change is which transport you pass to useChat . // components/chat-panel.tsx const { chatTransport } = useChatTransport ; const { messages, setMessages, sendMessage, stop, status } = useChat { id: tripId, transport: chatTransport, // Ably AI Transport, in place of the default HTTP transport } ; // Pull channel history, other participants, and any in-progress stream // into useChat, so a fresh tab or a new device catches up on mount. useMessageSync { setMessages } ; useView { limit: 30 } ; The transport is configured by wrapping the chat in a provider that points at this trip's session channel, trip: