The Active calls screen lists in-progress calls for the current org and offers a Supervise action on each row. This page explains what puts a call on that list, what the three supervisor modes do, the token and scope the gateway requires before it admits a supervisor, and which parts of the path are wired up today. Two queries back the screen:

What counts as an active call

telephony.listActiveCalls reads a per-org sorted set at telequick:<orgId>:active_calls, scored by call start time. A call row appears on the screen only if it survives every one of the following checks.
  1. Recency cutoff. The query reads the index with ZREVRANGEBYSCORE from +inf down to now - 60 minutes. Anything scored older than that is never considered. Real calls finish in seconds to minutes; an entry older than the cutoff is almost certainly a stale index row left behind by a hangup path that never removed it — a carrier disconnect, a gateway restart mid-call, or a Redis blip.
  2. Row limit. limit defaults to 100 and is capped at 500. The limit is applied both to the initial index read and to the final sorted result.
  3. End-record gate. For each candidate SID the procedure checks whether session:<sid>:end exists. agent_runtime writes that record on hangup (the RTP-listener silence-finalize / dialog-closure path). If the record exists, the call is over — even if release() failed to remove the SID from the index — and the call is treated as ended.
  4. Session hash present and tenant-matched. For each surviving SID the procedure reads tenant_id, agent_id, trunk_id, realm, started_at_ms, and node_id from session:<sid>. A row whose read errored, whose tenant_id is missing, or whose tenant_id does not equal the requesting orgId is dropped.
  5. Start time re-check. started_at_ms must parse to a finite number that is not older than the same 60-minute cutoff.
Surviving rows are sorted newest-first and truncated to limit.

Self-healing eviction

Candidates that failed the end-record gate are removed from the sorted set inline, as a best-effort pipelined ZREM. The cleanup is fire-and-forget: if it fails, those SIDs are simply filtered out again on the next listing, so the index converges without an external reaper.

Fields on each row

The duration shown in the row is computed client-side from started_at_ms, so it keeps ticking between the 8-second refreshes.

Supervisor modes: listen, whisper, barge-in

Clicking Supervise opens the supervise panel for that call_sid. The operator picks one of three modes. The console sends the mode to the control plane, which dispatches a Supervise op onto the per-tenant rpc_bridge queue; the gateway then records the supervisor as a participant on that session’s room.

Choosing the whisper target

Whisper mode requires a whisper_target naming which leg hears the supervisor:
  • agent — only the agent leg hears the supervisor.
  • caller — only the caller leg hears the supervisor.
Listen and barge-in ignore whisper_target. The requirement is enforced in both places: the control-plane procedure rejects a whisper request without a target, and the C++ rpc_bridge handler validates the same condition, so a request crafted against the gateway directly cannot bypass it.

Minting a supervisor token and the required scope

Supervision is not covered by an ordinary session credential. The console mints a short-lived, opaque supervisor token and hands it back to the gateway in SuperviseSubscribeRequest.auth_token. The gateway resolves the token at sa:<token> in Redis and admits the subscribe only if both conditions hold:
  • the token’s scopes contain telephony:supervise, and
  • the token’s tenant_id matches the tenant of the call being supervised.
Token properties: The regular agent role is deliberately not granted telephony:supervise. Supervising moves live call audio outside the per-call participant set, so it is modelled as an explicitly elevated action rather than something any agent identity picks up implicitly.

What works today and what is pending

The supervisor path ships in stages, and the Active calls screen is honest about which stage you are in. Working today
  • The active-call listing, liveness gating, and inline eviction described above.
  • Token minting with the role gate, call_sid binding, and 10-minute TTL.
  • Gateway admission: sa:<token> resolution, scope check, and tenant check.
  • Dispatch of the Supervise op onto the tenant’s rpc_bridge queue, and registration of the supervisor as a participant on the session room.
  • Mode and whisper_target validation, in the control plane and again in the C++ handler.
Pending
  • Audio routing is a no-op. Until the codec_engine mixer follow-up lands, joining as a supervisor does not move audio in either direction, for any of the three modes. The call returns SUPERVISOR_JOINED or SUPERVISOR_UPDATED so the console can confirm that the intent was accepted and render the pending state. Treat the Active calls screen as a read-only monitor for now.

Live engine telemetry ticker

The lower panel on the screen renders recent engine telemetry from monitoring.agentEvents, which reads an in-process ring buffer rather than the call index. The procedure takes a limit (default 50, maximum 200; the screen requests 40) and returns an enabled flag alongside the events. When the telemetry consumer is not enabled, the event list comes back empty. Each rendered line shows the event’s receive timestamp, its channel, and a flattened summary of the first few fields of the raw payload. tenant_id, org_id, ts, and timestamp are omitted from that summary because they are either redundant with the row context or already displayed. Payloads that do not parse as JSON are shown truncated. Pause stops the 3-second refresh entirely; the last fetched batch stays on screen until you resume.

Troubleshooting an empty or stale list

The list is empty but calls are in progress.
  • Confirm the session hash’s tenant_id matches the org you are viewing. Rows whose tenant_id differs from the requested orgId are filtered out silently.
  • Confirm the call was added to telequick:<orgId>:active_calls with a start-time score. A call absent from the index is invisible to this screen regardless of its real state.
  • Check for a premature session:<sid>:end record. Its presence is treated as proof the call ended, and the SID is evicted from the index on the spot.
A call that ended is still listed.
  • It will disappear on the next listing once session:<sid>:end is written, or once its start time passes the 60-minute cutoff. Eviction happens during a listing, so the self-heal requires at least one more poll.
  • Eviction is best-effort. If the cleanup pipeline fails, the entry remains in the index but stays filtered out of the response.
A long-running call disappeared.
  • Anything scored older than 60 minutes is outside the window and will not be listed, even if the call is genuinely still up. The 60-minute ceiling replaced a much wider window that surfaced hours-old hung-up calls to operators.
Rows look truncated.
  • The default limit is 100 and the maximum is 500. The limit bounds both the index read and the final result, so a very busy org sees the most recently started calls first.
Supervise accepted but nobody can hear anything. Supervise is rejected before the panel connects.
  • The minting identity must be an org owner or admin.
  • The token must carry telephony:supervise and a matching tenant_id.
  • The token is bound to one call_sid and lives 10 minutes; a token minted for a different call, or an expired one, is refused at the gateway.