useActiveTurns

Open in

Subscribe to the set of active turns on the channel. Returns a reactive Map keyed by clientId, where each value is a Set of turnIds for that client. Re-renders when turns start or end. Use it to drive UI such as a send-or-stop button, per-client streaming indicators, or a "wait for all turns to finish" guard.

This hook must be used within a TransportProvider or a ChatTransportProvider.

React

1

2

3

4

5

6

7

8

import { useActiveTurns } from '@ably/ai-transport/react';

function SendOrStop({ onSend, onStop }) {
  const activeTurns = useActiveTurns();
  return activeTurns.size > 0
    ? <button onClick={onStop}>Stop</button>
    : <button onClick={onSend}>Send</button>;
}

Parameters

transportoptionalClientTransport<TEvent, TMessage> or Null
Transport to track turns for. Defaults to the nearest provider when omitted.

Returns

Map<string, Set<string>>

A reactive map. The outer key is the clientId that owns the turns. The inner Set holds the turnIds currently active for that client.

Common patterns:

  • activeTurns.size > 0 — any turn is active anywhere on the channel.
  • activeTurns.has('agent-1') — a specific client (typically the agent) has at least one active turn.
  • activeTurns.get(clientId)?.size ?? 0 — how many turns a specific client has open.

The map updates in real time across every connected client, not just the local one. If another tab on the same session starts a turn, this hook's value updates in this component too.

Example

React

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

import { useActiveTurns, useView } from '@ably/ai-transport/react';
import { useState } from 'react';

function Composer() {
  const { send } = useView();
  const activeTurns = useActiveTurns();
  const [input, setInput] = useState('');

  const isStreaming = activeTurns.size > 0;

  const onSend = async () => {
    const text = input;
    setInput('');
    await send({ id: crypto.randomUUID(), role: 'user', parts: [{ type: 'text', text }] });
  };

  return (
    <form onSubmit={(e) => { e.preventDefault(); onSend(); }}>
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      {isStreaming
        ? <button type="button" disabled>Streaming…</button>
        : <button type="submit">Send</button>}
    </form>
  );
}