Agent presence
Your users see when the agent is thinking, streaming, idle, or offline. AI Transport channels carry Ably Presence, so an agent self-reports its state and every client sees it in real time.
Agent presence gives session participants a real-time view of which agents are active and what they are doing. Agent presence uses Ably's native Presence API on the AI Transport session channel. This works for a single orchestrator agent or a fleet of sub-agents, and conveys whether the agent is streaming, thinking, idle, or offline.
How it works
The agent enters presence on the AI Transport session channel with status data. As the agent moves through its turn lifecycle (receiving a message, thinking, streaming, finishing), it updates its presence data. Every connected client receives these updates in real time.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Server: agent enters presence when it connects.
const channel = ably.channels.get(sessionChannelName);
await channel.presence.enter({ status: 'idle' });
app.post('/api/chat', async (req, res) => {
const { turnId, clientId, messages } = req.body;
const turn = transport.newTurn({ turnId, clientId });
await channel.presence.update({ status: 'thinking' });
const result = streamText({
model: openai('gpt-4o'),
messages,
abortSignal: turn.abortSignal,
});
await channel.presence.update({ status: 'streaming' });
await turn.streamResponse(result.toUIMessageStream());
await channel.presence.update({ status: 'idle' });
res.json({ ok: true });
});Subscribe to agent status
On the client, subscribe to presence events to track the agent's current state:
1
2
3
4
5
6
7
8
9
10
const channel = ably.channels.get(sessionChannelName);
channel.presence.subscribe((member) => {
if (member.clientId === 'agent') {
console.log(`Agent is ${member.data.status}`);
}
});
const members = await channel.presence.get();
const agent = members.find((m) => m.clientId === 'agent');Combine presence with active turns
For richer status indicators, combine presence data with useActiveTurns. Presence tells you the agent's self-reported state. Active turns tell you which turns are in progress:
1
2
3
4
5
6
const activeTurns = useActiveTurns({ transport });
const agentStatus = useAgentPresence(channel); // your custom hook
const isStreaming = activeTurns.has('agent');
const isIdle = agentStatus === 'idle' && !isStreaming;
const isOffline = agentStatus === null;This is enough information for the UI to show a typing indicator while the agent thinks, a streaming animation while tokens arrive, and an offline badge when the agent disconnects.
Edge cases and unhappy paths
- An agent that exits without calling
presence.leave()(for example, a crashed process) is automatically removed from presence after a timeout. The agent is treated as present until the timeout fires. Wire a graceful shutdown that callsleavefor the best user experience. - A serverless agent that comes up for one turn and tears down should enter and leave presence per turn; entering once and leaving once at the end is fine for a long-running agent.
- Presence updates do not guarantee strict ordering with channel messages. A
streamingpresence update sometimes arrives slightly after the first token. Drive the UI off active turns for token-level state and use presence for higher-level status. - Multi-agent setups need unique
clientIdper agent. Two agents with the sameclientIdcollide in the presence set. - A client without
presencecapability cannot subscribe to updates. Capability scoping is part of authentication.
FAQ
Does presence cost a message?
Presence enter, update, and leave each consume a message on the channel. See the platform pricing for current rates.
Can clients enter presence too?
Yes. Presence is symmetric. A client that enters presence shows up alongside agents in the presence set. Use the clientId to distinguish.
How long does presence persist after a disconnect?
Until Ably's presence timeout fires (currently around 15 seconds). Active connections are not affected; this is for ungraceful disconnects.
What is the difference between presence and useActiveTurns?
Presence is self-reported by the agent. Active turns are observable from the channel by inspecting turn lifecycle events. Presence reports intent; active turns report fact. Both together produce richer status.
Can I pause inference when no users are connected?
Yes. Subscribe to presence and check whether any non-agent participants are present. If none, end the turn or short-circuit the LLM call. This is one of the cost-saving patterns presence enables.
Related features
- Presence: the Ably Presence API used for agent status.
- Concurrent turns: tracking active turns across clients.
- Multi-device sessions: presence works across every connected device.