Skip to content

feat(realtime): lean livekit_join with passthrough flag - #37

Open
VerioN1 wants to merge 1 commit into
mainfrom
feat/lean-livekit-join-passthrough
Open

feat(realtime): lean livekit_join with passthrough flag#37
VerioN1 wants to merge 1 commit into
mainfrom
feat/lean-livekit-join-passthrough

Conversation

@VerioN1

@VerioN1 VerioN1 commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

What

Implements the realtime-connect spec: the signaling-WS handshake no longer bundles initial state into the join, and the local track is no longer gated on the initial-state ack.

Connect sequence (new)

  1. Build initial state from session config.
  2. Open the signaling WebSocket.
  3. Send a lean livekit_join: { type, passthrough } — no nested initial_state.
  4. Immediately send the initial-state frame (set_image / prompt) as a separate message, without awaiting its ack.
  5. Await livekit_room_info.
  6. Connect to the LiveKit room.
  7. Publish the local track(s).
  8. Session reaches connected as soon as the room connects.
  9. Observe the initial-state ack out-of-band — surface an error event only on rejection. Steps 6–8 do not block on it.

This takes the (often multi-MB) image upload and its ack off the critical path to first frame.

passthrough flag

Required boolean on the join. Derived: false when the user set a real image/prompt, true otherwise. ConnectionConfig.passthrough (Bool?) overrides the derived value.

The ack timeout is armed only after room_info arrives, so a long queue_position wait can't trip it; acks landing before the observer starts are buffered.

Breaking change

ConnectionConfig.bundleInitialStateInJoin is removed and replaced by ConnectionConfig.passthrough (Bool?, default nil = derive).

Notes

  • Removed now-dead inline-ack senders (sendInitial*AndWait, waitForBundledInitialStateAck, handleInitialStateAfterRoomInfo) and the unused InitialStateMessage enum / sendMessage helper. Net −82 lines.

Test plan

  • swift build clean.
  • swift test — 96/96 pass, incl. new lean-join encoding tests and passthrough derivation tests (prompt/image/none/override).

🤖 Generated with Claude Code


Note

Medium Risk
Changes the realtime signaling contract and connect timing (breaking ConnectionConfig), which can affect server compatibility and when clients see connected vs initial-state errors.

Overview
Realtime connect now follows a lean signaling handshake: livekit_join sends only type and passthrough (no nested initial_state), then the SDK immediately sends the initial set_image / prompt as a separate WebSocket message. ConnectionConfig.bundleInitialStateInJoin is removed in favor of passthrough: Bool? (derive from prompt/image when nil).

Connect no longer waits on the initial-state ack before LiveKit connect/publish; observeInitialStateAck runs after room_info so queue time does not consume the ack timeout, with early acks buffered via isWaitingForInitialStateAck. Session connected is reached when the room is up; ack failures are handled out-of-band (logged, not blocking performConnect). Empty sessions always bootstrap with a passthrough set_image via buildInitialStateRequest().

Tests cover lean join JSON and passthrough derivation/overrides.

Reviewed by Cursor Bugbot for commit e232327. Bugbot is set up for automated code reviews on this repo. Configure here.

Reverse the bundle-initial-state-in-join design so the initial-state
upload and its ack no longer gate the local track.

- Send a lean `livekit_join` carrying only `{ type, passthrough }`.
- Fire the initial-state frame (set_image / prompt / null-bootstrap) as a
  separate message immediately after the join, without awaiting its ack.
- Connect the room and publish the local track as soon as room_info
  arrives; observe the ack out-of-band and surface an error only on
  rejection. Its timeout is armed after room_info so a long queue wait
  can't trip it.
- Derive `passthrough` from the initial prompt/image (override via
  ConnectionConfig.passthrough).

BREAKING: ConnectionConfig.bundleInitialStateInJoin is replaced by
ConnectionConfig.passthrough (Bool?).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e232327. Configure here.

clearPendingInitialState()
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Runtime prompts lose acks after connect

High Severity

connect can finish while isWaitingForInitialStateAck is still true. Any setPrompt/setImage in that window routes acks into the initial-state buffer; when the observer completes, clearPendingInitialState() drops unmatched acks, so runtime waiters time out or hang even though the server responded.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e232327. Configure here.

return
} catch {
DecartLogger.log("Initial-state acknowledgment failed: \(error.localizedDescription)", level: .error)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Initial ack timeout marks error

Medium Severity

The out-of-band initial-state observer reuses waitForPromptAck/waitForSetImageAck, which set connectionState to .error on timeout. After a successful connect, a late initial-state ack timeout can flip an already-connected session to error, though the PR describes surfacing errors only on server rejection.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e232327. Configure here.

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.

1 participant