OrbSignal describes
what the conversation is doing, and OrbAdapter delivers those signals and optionally controls the
session.
The actual signal contract
These are the public types exported byorb-ui and orb-ui/adapters:
subscribe must return a cleanup function. Emit a complete current signal, not a partial patch:
orb-ui stores the latest object as the adapter signal. start and stop are optional because an
app may already own the session controls.
Normalize provider states at the boundary
Keep provider-specific names out of components. Map them once in the adapter:error for the normalized UI state and attach the original failure to signal.error for logs
or nearby error messaging. Do not invent provider-specific visual states unless the product needs
to render them differently.
Input volume and output volume are different signals
Normalize audio levels to0–1. inputVolume represents the user’s microphone; outputVolume
represents assistant playback. Keeping them separate prevents microphone noise from animating the
orb while the assistant is speaking.
Orb selects inputVolume in listening and outputVolume in speaking. It uses zero outside
those states. There is no directionless volume field: a stable signal contract lets every theme
interpret the same input and output semantics.
Clamp provider values before emitting them:
Adapter mode versus controlled mode
Use adapter mode when a provider client owns events and session lifecycle. Without an explicitaria-label, orb-ui supplies the matching “Start voice session” or “Stop voice session” label:
state prop can override signal or adapter state, but prefer one ownership model per component.
Controlled mode is the shortest route for a one-off integration. An adapter becomes valuable when
the mapping, calibration, and cleanup logic is reused.
Build a real custom adapter
This example wraps a small event-driven voice session. It keeps one current signal, supports multiple subscribers, removes provider listeners when the final orb unsubscribes, and exposes the session controls.Choose and migrate deliberately
- Choose a built-in provider adapter when it matches your provider and desired session ownership.
- Start in controlled mode when your existing store already exposes normalized state and volume.
- Extract a custom adapter when provider event mapping, lifecycle, or audio normalization begins to leak into multiple React components.
- When migrating from the callback-object adapter removed in orb-ui 0.5.0, replace
subscribe({ onStateChange, onVolumeChange })withsubscribe(listener)and emitOrbSignalobjects. Split the old single volume into input and output meters when the provider exposes both.
debug theme first. Verify every provider state, unsubscribe cleanup,
start/stop failures, and that only the active speaker’s meter drives the UI.