Skip to content

fix(client): tolerate transient control-poll failures in useVoice - #39

Merged
jerelvelarde merged 2 commits into
CopilotKit:mainfrom
sx4im:fix/voice-control-poll-grace
Oct 5, 2026
Merged

jerelvelarde merged 2 commits into
CopilotKit:mainfrom
sx4im:fix/voice-control-poll-grace

Conversation

@sx4im

@sx4im sx4im commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

What

useVoice polls GET /voice/calls/:id every 2 seconds. The .catch() on that poll set Call control connection was lost. and ended the call on the first failure, so a short network flap hung up a call the peer would have recovered from. #26 adds a five-second grace period for RTCPeerConnection disconnected but does not cover this path.

Changes

  • src/client/useVoice.ts: count consecutive control-poll failures on the session. The call ends after three in a row; a successful poll resets the count. Same idea as the grace period in fix: allow voice connections five seconds to recover #26.
  • tests/use-voice-control-poll.test.ts: regression tests with a mocked peer, media, and API. One failed poll keeps the call alive, a later success resets the count, and three consecutive failures end the call exactly once with Call control connection was lost.
  • Added react-test-renderer and its types as dev dependencies for the hook tests, same as fix: allow voice connections five seconds to recover #26.

Tradeoff

If the server is really gone, the call now stays up for about six more seconds before ending. The design question in #38 is still open, so say the word if you want a different threshold or one window shared with the peer state.

Tests

New tests fail on the base commit (2 failed, 2 passed) and pass with the change (4 passed). Full suite: 166/168 pass; the 2 failures are tests/transport.test.ts (DNS-pinned transport needs live network) and fail on the base commit too. npm run check-format, npm run lint, npm run typecheck, and npm run build all pass.

Fixes #38

A single failed GET /voice/calls/:id poll ended the call immediately,
even for a short network flap the peer would have recovered from.
Track consecutive poll failures on the session and only declare the
control connection lost after three in a row; any successful poll
resets the count. Mirrors the grace period CopilotKit#26 gives the peer
connection. Adds regression tests covering the new behavior.

Fixes CopilotKit#38

@NathanTarbert NathanTarbert left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sx4im, and thanks for building on #26 rather than opening a competing fix. Ending on the third failure in a row lines up nicely with #26's five seconds. The test that checks the call ends exactly once is the one I'd most want to see here.

On the open question about one shared window: with this and #26 merged together, the two separate windows already behave the way #38 asks for. A short drop on both sides leaves the call up. A poll-only flap with a healthy peer leaves the call up. A lasting outage ends the call once, with the peer's message, because its five seconds runs out first. jibraaan's shared window on #38 would be tidier, with one timer and one message. It doesn't look necessary for correctness, so I'd be happy either way.

The only friction is that both PRs add a field next to timer in the session in useVoice.ts. If #26 goes in first, the rebase here is just keeping both lines.

Looks good to me.

@NathanTarbert

Copy link
Copy Markdown
Contributor

Heads up @sx4im, #26 is merged now, so this needs the small rebase in useVoice.ts, keeping both session fields next to timer.

@jerelvelarde jerelvelarde left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useful resilience improvement: transient control-poll failures no longer immediately end a voice call, while repeated failures remain bounded. Fits the existing voice lifecycle and preserves the current disconnect grace timer after conflict resolution. No actionable security or correctness findings. Validated the integrated branch with 201 tests, type checking, lint, formatting, and production build; the five-PR combined tree passes 233 tests and the same checks.

@jerelvelarde
jerelvelarde merged commit ed05fbb into CopilotKit:main Oct 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Control-poll failure ends a call immediately, even if the peer would recover

3 participants