What's Changed
- docs(changelog): promote Unreleased to 0.38.0
- feat(skills): unavailable skills stay visible with a reason (LUG-281)
- fix(typing): the optional SDK's nominal mismatch is cast away, not suppressed
- docs(conference): the realtime example lets the caller pick the voice (RMK-77)
- docs(conference): the realtime path skips the attribution STT by default (RMK-77)
- docs(conference): the livekit example joins the speech-to-speech meeting (RMK-77)
- fix(conference): the livekit example asks ElevenLabs for PCM, not mp3 (RMK-78)
- fix(conference): the livekit example names its model — the provider default retired (RMK-78)
- docs(conference): the speech-to-speech meeting, runnable end to end (RMK-77)
- test(conference): the speech-to-speech composition proves its contracts (RMK-77)
- feat(conference): the realtime provider joins the meeting — speech-to-speech N→1 (RMK-77)
- feat(conference): the mix a speech-to-speech provider hears (RMK-77)
- refactor(conference): the utterance pump takes any chunk stream (RMK-77)
- docs(conference): the AI answers the meeting — the real STT→LLM→TTS loop (RMK-78)
- fix(typing): the type gate clears the optional SDKs' stub drift
- fix(conference): the grant instruction waits for a join in flight (RMK-79)
- feat(conference): explicit bot grants are owned, and their owner speaks at runtime (RMK-79)
- style(examples): format the notetaker example (RMK-76)
- refactor(conference): the transport-only docstring speaks in the present (RMK-76)
- fix(conference): a plugged recognizer reaches the tracks recording subscribed first (RMK-76)
- docs(conference): the notetaker-on-demand example (RMK-76)
- feat(conference): intelligence plugs into and out of a running channel (RMK-76)
- feat(conference): a connected bot session's grants can change in place (RMK-76)
- refactor(conference): the pure-transport tests settle joins with the shared helper (RMK-75)
- refactor(conference): the arrival test's docstring speaks in the present (RMK-75)
- feat(conference): the bot only joins when something consumes or speaks (RMK-75)
- docs(conference): the mock and LiveKit examples the guide cites (RMK-5)
- feat(conference): track publications name their kind, like the mute pair
- feat(conference): a publisher's mute is presence the room gets to hear about
- feat(conference): the management surface — speech edges, quality, names, renames (RMK-73)
- feat(conference): the occupancy probe names its reason before joining (RMK-71)
- fix(conference): an attach over a live conference is itself a first need (RMK-71)
- docs(changelog): record the mid-loop read_stored_result fix (#17)
- fix(ai): make read_stored_result callable in the turn that evicted
- docs(examples): the VAD models moved to the asr-models release
- fix(conference): a credential going out is what starts the first bot join (RMK-68)
- feat(conference): give the framework a way to stop the bot's playback (RMK-66)
- docs(security): return SECURITY.md to being a disclosure policy
- docs(conference): the code stops calling a STABLE section provisional
- docs(changelog): two coherence fixes on the conference entry
- feat(sip): make symmetric_rtp reachable, and say what it actually covers
- fix(conference): rounds 2-4 of the SFU review — reservations, recovery, honest loss
- fix(sip): release the session when a 2xx is never acknowledged
- docs(changelog): record the phase-3 hygiene fixes
- chore(deps): raise the security-relevant floors, and audit the extras
- docs(hooks): say which triggers fail closed, and note the mutable model URL
- docs(webhooks): point integrators at the signature check that already exists (E2)
- fix(config): keep secrets out of config repr (L5, RFC §17.7)
- feat(twilio): give the RCS provider the signature check SMS already had (L4)
- fix(ai): stop broadcasting the provider's error text into the room (L2)
- docs(identity): say what participant_id is worth without a resolver (M3)
- fix(sources): keep a source's token out of its name, logs and events (M8)
- fix(voice): bound the outbound audio queues, cap the binary inbound frame (M6, L3)
- fix(websocket): bound the fan-out so one dead socket cannot freeze a room (M5)
- fix(conference): the SFU review remediated — a backend that tells the truth
- feat(websocket)!: scope connections to rooms, and deliver only there (M4)
- docs(agents): record where a subsystem backend lives (RMK-23)
- fix(core): the inbound router refuses to guess an ambiguous room (RFC §10.4)
- fix(core): a closed room refuses new events (RFC §5.1, §10.1 step 6)
- fix(core): a derived binding never grants more than its origin (RFC §7.5-6, §7.5-7)
- docs(sip): state the trust model the SIP backend is built on
- fix(sip): constant-time digest compare, bounded nonce sweep, redacted traces
- fix(sip): validate the RTP destination an offer asks for (M-SIP-1)
- feat(xai): a Grok chat provider beside the realtime one
- fix(sip): bound the lifecycle of a call that never sends RTP (H3)
- fix(sip): refuse an INVITE that claims a live session id (H2)
- fix(conference): one shutdown, lease-gated closes, exact-once departures (RFC 12.10.4)
- feat(webtransport)!: authenticate the CONNECT handshake, refuse silent anonymity
- fix(examples): validate the Teams webhook JWT before trusting the body
- fix(core): fail closed on edit/delete authorization (RFC §10.3)
- fix(video/sip): an m=video line no longer skips INVITE authentication
- refactor(conference): give the bot's voice track its own module per review (RMK-23)
- feat(conference): a real SFU backend on LiveKit (RMK-23)
- feat(conference): multi-party conferences on an external SFU (RFC 12.10, RMK-1..RMK-65)
- fix(cli): declare the terminal's sender as a participant, not an address (RMK-22)
- feat(pipeline)!: key every audio stage on a stream identity (RMK-16, RMK-17)
- ci(dependabot): ignore numpy — uv updater crashes on our multi-declaration
- Begin 0.38.0.dev0 development
Full Changelog: v0.37.1...v0.38.0