Agent presence

Open in

Agent presence provides a realtime view to other session participants so they can know which agents are active in a session. Agent presence uses Ably's native Presence API to show real-time agent status in your application, and this could include a sole or orcestrator agent, or multiple sub-agents. Presence can convey whether the agent is streaming, thinking, idle, or offline - across all connected clients.

Diagram showing presence-aware agent status updates

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. All connected clients receive these updates in real time.

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

// Server: agent enters presence when it connects
const channel = ably.channels.get(sessionChannelName)
await channel.presence.enter({ status: 'idle' })

// Update status during each turn lifecycle
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:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

const channel = ably.channels.get(sessionChannelName)

channel.presence.subscribe((member) => {
  if (member.clientId === 'agent') {
    console.log(`Agent is ${member.data.status}`)
  }
})

// Get the current presence set
const members = await channel.presence.get()
const agent = members.find(m => m.clientId === 'agent')

Combine 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:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

const activeTurns = useActiveTurns(transport)
const agentStatus = useAgentPresence(channel) // your custom hook

// Agent is streaming if it has active turns
const isStreaming = activeTurns.has('agent')

// Agent is online but idle if present with no active turns
const isIdle = agentStatus === 'idle' && !isStreaming

// Agent is offline if not in the presence set
const isOffline = agentStatus === null

This gives the UI enough information to show a typing indicator while the agent is thinking, a streaming animation while tokens are arriving, and an offline badge when the agent disconnects.