@lofcz/orb-ui 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +330 -0
  3. package/dist/adapters/audio-level.d.ts +28 -0
  4. package/dist/adapters/elevenlabs/index.d.ts +85 -0
  5. package/dist/adapters/gemini-live/index.d.ts +70 -0
  6. package/dist/adapters/index.d.ts +8 -0
  7. package/dist/adapters/livekit/browser.d.ts +49 -0
  8. package/dist/adapters/livekit/index.d.ts +136 -0
  9. package/dist/adapters/openai-realtime/index.d.ts +37 -0
  10. package/dist/adapters/pipecat/index.d.ts +62 -0
  11. package/dist/adapters/types.d.ts +7 -0
  12. package/dist/adapters/vapi/index.d.ts +42 -0
  13. package/dist/adapters.cjs +1 -0
  14. package/dist/adapters.js +829 -0
  15. package/dist/components/Orb/Orb.d.ts +2 -0
  16. package/dist/components/Orb/Orb.types.d.ts +87 -0
  17. package/dist/components/Orb/index.d.ts +2 -0
  18. package/dist/components/Orb/signals.d.ts +3 -0
  19. package/dist/index.d.ts +4 -0
  20. package/dist/livekit-D-s4sYba.cjs +1 -0
  21. package/dist/livekit-Z3IMmWaG.js +316 -0
  22. package/dist/livekit-adapter.cjs +1 -0
  23. package/dist/livekit-adapter.js +30 -0
  24. package/dist/orb-ui.cjs +203 -0
  25. package/dist/orb-ui.js +984 -0
  26. package/dist/themes/bars/BarsTheme.d.ts +14 -0
  27. package/dist/themes/bars/index.d.ts +1 -0
  28. package/dist/themes/circle/CircleTheme.d.ts +14 -0
  29. package/dist/themes/circle/index.d.ts +1 -0
  30. package/dist/themes/cloud/CloudTheme.d.ts +14 -0
  31. package/dist/themes/cloud/index.d.ts +1 -0
  32. package/dist/themes/debug/DebugTheme.d.ts +15 -0
  33. package/dist/themes/debug/index.d.ts +1 -0
  34. package/dist/themes/index.d.ts +5 -0
  35. package/dist/themes/radial/RadialTheme.d.ts +13 -0
  36. package/dist/themes/radial/index.d.ts +1 -0
  37. package/package.json +122 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alexander Chen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,330 @@
1
+ # orb-ui
2
+
3
+ **Voice agent UI that feels alive.**
4
+
5
+ Expressive, accessible React components for realtime voice agents. Connect Vapi, ElevenLabs, LiveKit, Pipecat, OpenAI Realtime, Gemini Live, or your own voice stack through one consistent UI layer.
6
+
7
+ <p align="center">
8
+ <a href="https://orb-ui.com">
9
+ <img src="demo/public/og-image-v2.jpg" alt="orb-ui — Voice agent UI that feels alive" width="900" />
10
+ </a>
11
+ </p>
12
+
13
+ <p align="center">
14
+ <a href="https://orb-ui.com">Live demo</a> · <a href="https://orb-ui.com/docs">Documentation</a> · <a href="https://orb-ui.com/playground">Playground</a> · <a href="https://www.npmjs.com/package/@lofcz/orb-ui">npm</a> · <a href="https://github.com/lofcz/orb-ui">Star on GitHub</a>
15
+ </p>
16
+
17
+ ```jsx
18
+ import Vapi from '@vapi-ai/web'
19
+ import { Orb } from '@lofcz/orb-ui'
20
+ import { createVapiAdapter } from '@lofcz/orb-ui/adapters'
21
+
22
+ const vapi = new Vapi('your-public-key')
23
+ const adapter = createVapiAdapter(vapi, { assistantId: 'your-assistant-id' })
24
+
25
+ export function VoiceOrb() {
26
+ return <Orb adapter={adapter} theme="circle" aria-label="Start voice assistant" />
27
+ }
28
+ ```
29
+
30
+ ## Install
31
+
32
+ Install the component package:
33
+
34
+ ```bash
35
+ bun add @lofcz/orb-ui
36
+ ```
37
+
38
+ Provider adapters are lightweight wrappers around provider SDKs. Install the SDK for the provider you use:
39
+
40
+ ```bash
41
+ # Vapi
42
+ bun add @lofcz/orb-ui @vapi-ai/web
43
+
44
+ # ElevenLabs Conversational AI
45
+ bun add @lofcz/orb-ui @elevenlabs/client
46
+
47
+ # LiveKit Agents
48
+ bun add @lofcz/orb-ui livekit-client
49
+
50
+ # Pipecat (choose the transport used by your agent)
51
+ bun add @lofcz/orb-ui @pipecat-ai/client-js @pipecat-ai/small-webrtc-transport
52
+
53
+ # OpenAI Realtime uses browser WebRTC and has no additional client SDK
54
+ bun add @lofcz/orb-ui
55
+
56
+ # Gemini Live
57
+ bun add @lofcz/orb-ui @google/genai
58
+ ```
59
+
60
+ > **Note:** Orb uses React hooks internally — in Next.js App Router, use it in a `'use client'` component.
61
+
62
+ ## How provider adapters are created
63
+
64
+ Every provider ends at the same React API:
65
+
66
+ ```jsx
67
+ <Orb adapter={adapter} theme="circle" aria-label="Start voice assistant" />
68
+ ```
69
+
70
+ The only difference is how the adapter obtains a provider session:
71
+
72
+ | Provider | Required browser setup |
73
+ | ------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
74
+ | [Vapi guide](https://orb-ui.com/docs/adapters/vapi) | Pass a configured Vapi client plus `assistantId` |
75
+ | [ElevenLabs guide](https://orb-ui.com/docs/adapters/elevenlabs) | Pass `Conversation` plus an `agentId`, signed URL, or conversation token |
76
+ | [LiveKit guide](https://orb-ui.com/docs/adapters/livekit) | Provide a token endpoint and optional agent name |
77
+ | [Pipecat guide](https://orb-ui.com/docs/adapters/pipecat) | Pass a configured `PipecatClient` plus its connect callback |
78
+ | [OpenAI Realtime guide](https://orb-ui.com/docs/adapters/openai-realtime) | Return a fresh short-lived client secret from `getClientSecret` |
79
+ | [Gemini Live guide](https://orb-ui.com/docs/adapters/gemini-live) | Open the official Google Live session in `connect` |
80
+
81
+ The adapter owns provider event mapping and emits one consistent `OrbSignal`. OpenAI and Gemini
82
+ standard API keys, and LiveKit participant-token signing, stay on your server. See the
83
+ [adapter overview](https://orb-ui.com/docs/adapters/overview) for the responsibility boundary and
84
+ advanced setup shapes.
85
+
86
+ For an app-owned WebRTC, WebSocket, telephony, or speech runtime, follow the
87
+ [custom integration guide](https://orb-ui.com/docs/adapters/custom).
88
+
89
+ ## Quick Start
90
+
91
+ Use orb-ui as a React voice AI component when you need a first-party provider voice UI or a custom animated voice orb for another realtime voice agent stack.
92
+
93
+ ### With Vapi
94
+
95
+ ```jsx
96
+ import Vapi from '@vapi-ai/web'
97
+ import { Orb } from '@lofcz/orb-ui'
98
+ import { createVapiAdapter } from '@lofcz/orb-ui/adapters'
99
+
100
+ const vapi = new Vapi('your-public-key')
101
+ const adapter = createVapiAdapter(vapi, { assistantId: 'your-assistant-id' })
102
+
103
+ function App() {
104
+ return <Orb adapter={adapter} theme="circle" aria-label="Start Vapi assistant" />
105
+ }
106
+ ```
107
+
108
+ ### With ElevenLabs
109
+
110
+ ```jsx
111
+ import { Conversation } from '@elevenlabs/client'
112
+ import { Orb } from '@lofcz/orb-ui'
113
+ import { createElevenLabsAdapter } from '@lofcz/orb-ui/adapters'
114
+
115
+ const adapter = createElevenLabsAdapter(Conversation, { agentId: 'your-agent-id' })
116
+
117
+ function App() {
118
+ return <Orb adapter={adapter} theme="circle" aria-label="Start ElevenLabs assistant" />
119
+ }
120
+ ```
121
+
122
+ ### With LiveKit
123
+
124
+ ```jsx
125
+ import { Orb } from '@lofcz/orb-ui'
126
+ import { createLiveKitAdapter } from '@lofcz/orb-ui/adapters/livekit'
127
+
128
+ const adapter = createLiveKitAdapter({
129
+ tokenEndpoint: '/api/livekit-token',
130
+ agentName: 'your-agent-name',
131
+ })
132
+
133
+ function App() {
134
+ return <Orb adapter={adapter} theme="circle" aria-label="Start LiveKit assistant" />
135
+ }
136
+ ```
137
+
138
+ The LiveKit entrypoint creates the room and token source, assigns a fresh room name, and meters both
139
+ sides of the conversation with speech-oriented analyser and smoothing defaults. Existing-room and
140
+ custom-runtime modes remain available from the advanced `@lofcz/orb-ui/adapters` entrypoint.
141
+
142
+ ### With Pipecat
143
+
144
+ ```jsx
145
+ import { PipecatClient } from '@pipecat-ai/client-js'
146
+ import { SmallWebRTCTransport } from '@pipecat-ai/small-webrtc-transport'
147
+ import { Orb } from '@lofcz/orb-ui'
148
+ import { createPipecatAdapter } from '@lofcz/orb-ui/adapters'
149
+
150
+ const client = new PipecatClient({ transport: new SmallWebRTCTransport(), enableMic: true })
151
+ const adapter = createPipecatAdapter(client, {
152
+ connect: () => client.connect({ webrtcUrl: 'https://agent.example.com/api/offer' }),
153
+ })
154
+
155
+ function App() {
156
+ return <Orb adapter={adapter} theme="circle" aria-label="Start Pipecat assistant" />
157
+ }
158
+ ```
159
+
160
+ The Pipecat adapter consumes the standard RTVI event surface and meters the client media tracks as
161
+ a browser fallback, so it works with Pipecat Cloud, Daily, SmallWebRTC, and transports that emit
162
+ sparse audio-level events. See the [Pipecat guide](https://orb-ui.com/docs/adapters/pipecat).
163
+
164
+ ### With OpenAI Realtime
165
+
166
+ ```jsx
167
+ import { Orb } from '@lofcz/orb-ui'
168
+ import { createOpenAIRealtimeAdapter } from '@lofcz/orb-ui/adapters'
169
+
170
+ const adapter = createOpenAIRealtimeAdapter({
171
+ getClientSecret: async () => {
172
+ const response = await fetch('/api/openai-realtime-token', { method: 'POST' })
173
+ return (await response.json()).value
174
+ },
175
+ })
176
+ ```
177
+
178
+ Create client secrets with a standard OpenAI API key on your server. See the
179
+ [OpenAI Realtime guide](https://orb-ui.com/docs/adapters/openai-realtime).
180
+
181
+ ### With Gemini Live
182
+
183
+ ```jsx
184
+ import { GoogleGenAI } from '@google/genai'
185
+ import { Orb } from '@lofcz/orb-ui'
186
+ import { createGeminiLiveAdapter } from '@lofcz/orb-ui/adapters'
187
+
188
+ const adapter = createGeminiLiveAdapter({
189
+ connect: async (callbacks) => {
190
+ const token = await fetch('/api/gemini-live-token', { method: 'POST' }).then((res) =>
191
+ res.json(),
192
+ )
193
+ const client = new GoogleGenAI({
194
+ apiKey: token.value,
195
+ httpOptions: { apiVersion: 'v1alpha' },
196
+ })
197
+ return client.live.connect({ model: token.model, config: token.config, callbacks })
198
+ },
199
+ })
200
+ ```
201
+
202
+ Mint one-use Gemini Live tokens on your server. See the
203
+ [Gemini Live guide](https://orb-ui.com/docs/adapters/gemini-live) for the matching server config that
204
+ disables automatic activity detection. The adapter handles client-side turn detection by default.
205
+
206
+ The examples above show the intended happy paths. Transport overrides, custom browser runtimes,
207
+ existing-session modes, and audio calibration hooks are optional and documented in the individual
208
+ adapter guides.
209
+
210
+ ### Controlled mode (custom integration)
211
+
212
+ ```jsx
213
+ import { Orb } from '@lofcz/orb-ui'
214
+ import { useState } from 'react'
215
+
216
+ function App() {
217
+ const [state, setState] = useState('idle')
218
+ const [volume, setVolume] = useState(0)
219
+
220
+ return <Orb state={state} volume={volume} theme="circle" />
221
+ }
222
+ ```
223
+
224
+ Use `signal` when your integration has separate input and output levels:
225
+
226
+ ```jsx
227
+ import { Orb } from '@lofcz/orb-ui'
228
+
229
+ function App() {
230
+ return <Orb signal={{ state: 'speaking', outputVolume: 0.7 }} theme="circle" />
231
+ }
232
+ ```
233
+
234
+ ### External session controls
235
+
236
+ Keep the orb as a passive visual when start and stop controls belong elsewhere in your layout.
237
+ Provider adapters already expose the matching lifecycle methods.
238
+
239
+ ```jsx
240
+ function VoiceExperience({ adapter }) {
241
+ return (
242
+ <>
243
+ <Orb adapter={adapter} theme="cloud" interactive={false} />
244
+ <button onClick={() => void adapter.start?.()}>Start conversation</button>
245
+ <button onClick={() => void adapter.stop?.()}>End conversation</button>
246
+ </>
247
+ )
248
+ }
249
+ ```
250
+
251
+ ## Themes
252
+
253
+ | Theme | Description |
254
+ | -------- | ----------------------------------------------------------------------------- |
255
+ | `radial` | Four-lobe radial field with input-reactive rim and output-reactive twisting. |
256
+ | `cloud` | Atmospheric sphere with inverse listening scale and faster speaking motion. |
257
+ | `debug` | State + volume display with start/stop. Use to verify your integration works. |
258
+ | `circle` | Pulsing circle that reacts to volume. |
259
+ | `bars` | Five bars that animate with voice. |
260
+
261
+ When an adapter or `onStart`/`onStop` handler is provided, visual themes include keyboard-accessible `<button type="button">` controls. `radial` places its phone control below the artwork while the other clickable themes use the visual itself. Pass `interactive={false}` to keep the theme passive and call `adapter.start()` or `adapter.stop()` from external controls instead.
262
+
263
+ The radial phone control uses a small cutout that defaults to white. Match it to the surface behind
264
+ the orb with the typed style variable:
265
+
266
+ ```tsx
267
+ <Orb adapter={adapter} theme="radial" style={{ '--orb-ui-radial-control-surround': '#101010' }} />
268
+ ```
269
+
270
+ ## Props
271
+
272
+ | Prop | Type | Default | Description |
273
+ | ------------- | ------------------------------------------------------ | --------- | ------------------------------------------------------- |
274
+ | `theme` | `'debug' \| 'circle' \| 'bars' \| 'cloud' \| 'radial'` | `'debug'` | Visual theme |
275
+ | `signal` | `OrbSignal` | — | Rich controlled signal with state/input/output volume |
276
+ | `state` | `OrbState` | `'idle'` | Conversation state (controlled mode) |
277
+ | `volume` | `number` | `0` | Audio volume, 0–1. Overrides signal/adapter volume. |
278
+ | `adapter` | `OrbAdapter` | — | Provider adapter (manages signal updates automatically) |
279
+ | `size` | `number` | `200` | Size in pixels |
280
+ | `className` | `string` | — | Optional class name for the rendered theme |
281
+ | `style` | `OrbStyle` | — | Inline styles, including radial control surround color |
282
+ | `disabled` | `boolean` | `false` | Disables clickable themes and debug start/stop controls |
283
+ | `interactive` | `boolean` | `true` | Allows the theme control to start and stop a session |
284
+ | `aria-label` | `string` | generated | Accessible label for clickable visual themes |
285
+ | `onStart` | `() => void` | — | Custom start handler (overrides adapter.start()) |
286
+ | `onStop` | `() => void` | — | Custom stop handler (overrides adapter.stop()) |
287
+
288
+ ## States
289
+
290
+ `idle` · `connecting` · `listening` · `thinking` · `speaking` · `error`
291
+
292
+ ## Supported Providers
293
+
294
+ | Provider | Adapter |
295
+ | ------------------------------------------------------------------------- | --------------------------------------------------------------------- |
296
+ | [Vapi](https://vapi.ai) | `createVapiAdapter` from `@lofcz/orb-ui/adapters` |
297
+ | [ElevenLabs](https://elevenlabs.io/conversational-ai) | `createElevenLabsAdapter` from `@lofcz/orb-ui/adapters` |
298
+ | [LiveKit](https://livekit.io) | `createLiveKitAdapter` from `@lofcz/orb-ui/adapters` |
299
+ | [Pipecat](https://pipecat.ai) | `createPipecatAdapter` from `@lofcz/orb-ui/adapters` |
300
+ | [OpenAI Realtime](https://developers.openai.com/api/docs/guides/realtime) | `createOpenAIRealtimeAdapter` from `@lofcz/orb-ui/adapters` |
301
+ | [Gemini Live](https://ai.google.dev/gemini-api/docs/live-api) | `createGeminiLiveAdapter` from `@lofcz/orb-ui/adapters` |
302
+ | Custom | Use controlled mode — pass `signal`, or `state` and `volume` directly |
303
+
304
+ ## Development
305
+
306
+ ```bash
307
+ git clone https://github.com/lofcz/orb-ui.git
308
+ cd orb-ui
309
+ bun install
310
+
311
+ # Build the library
312
+ bun run build
313
+
314
+ # Run demo locally
315
+ bun run dev:demo
316
+ ```
317
+
318
+ Useful maintenance commands:
319
+
320
+ ```bash
321
+ bun run check # format check, lint, typechecks, tests, library build, demo build
322
+ bun run format # format repo files
323
+ ```
324
+
325
+ Releases are published as `@lofcz/orb-ui` from GitHub Actions (`release.yml`)
326
+ using npm trusted publishing (OIDC). Run **Release and Publish to npm** on `main`.
327
+
328
+ ## License
329
+
330
+ MIT © [Alexander Chen](https://github.com/alexanderqchen)
@@ -0,0 +1,28 @@
1
+ export interface OutputVolumeCalibration {
2
+ /** Raw RMS values at or below this level are treated as silence. */
3
+ noiseFloor: number;
4
+ /** Multiplier applied after the noise floor. */
5
+ gain: number;
6
+ /** Power curve applied after gain. Values below 1 lift quieter speech. */
7
+ exponent: number;
8
+ /** EMA rate used while the volume is rising. */
9
+ attack: number;
10
+ /** EMA rate used while the volume is falling. */
11
+ release: number;
12
+ }
13
+ export type OutputVolumeCalibrationSource = Partial<OutputVolumeCalibration> | (() => Partial<OutputVolumeCalibration>);
14
+ export interface OutputVolumeSample {
15
+ /** Unmodified RMS value measured from the provider audio stream. */
16
+ raw: number;
17
+ /** Value after noise floor, gain, and power-curve shaping. */
18
+ shaped: number;
19
+ /** Final value after attack/release smoothing. */
20
+ normalized: number;
21
+ }
22
+ export interface MediaStreamTrackVolumeMeter {
23
+ stop(): Promise<void>;
24
+ }
25
+ export type AudioContextSource = () => AudioContext | undefined;
26
+ export declare const DEFAULT_OUTPUT_VOLUME_CALIBRATION: OutputVolumeCalibration;
27
+ export declare function calibrateOutputVolume(rawValue: number, previous: number, source?: OutputVolumeCalibrationSource): OutputVolumeSample;
28
+ export declare function createMediaStreamTrackVolumeMeter(track: MediaStreamTrack, createAudioContext: AudioContextSource, onVolume: (volume: number) => void): MediaStreamTrackVolumeMeter | undefined;
@@ -0,0 +1,85 @@
1
+ import { OrbAdapter } from '../types.js';
2
+ export type ElevenLabsMode = 'speaking' | 'listening';
3
+ export type ElevenLabsStatus = 'disconnected' | 'connecting' | 'connected' | 'disconnecting';
4
+ export type ElevenLabsConnectionType = 'websocket' | 'webrtc';
5
+ export interface ElevenLabsCallbacks {
6
+ onConnect?: (props: {
7
+ conversationId: string;
8
+ }) => void;
9
+ onDisconnect?: (details: unknown) => void;
10
+ onError?: (message: string, context?: unknown) => void;
11
+ onModeChange?: (prop: {
12
+ mode: ElevenLabsMode;
13
+ }) => void;
14
+ onStatusChange?: (prop: {
15
+ status: ElevenLabsStatus;
16
+ }) => void;
17
+ onVadScore?: (props: {
18
+ vadScore: number;
19
+ }) => void;
20
+ }
21
+ export interface ElevenLabsConversation {
22
+ endSession(): Promise<void>;
23
+ getInputVolume(): number;
24
+ getOutputVolume(): number;
25
+ getInputByteFrequencyData(): Uint8Array;
26
+ getOutputByteFrequencyData(): Uint8Array;
27
+ }
28
+ type ElevenLabsSessionAuth = {
29
+ agentId: string;
30
+ signedUrl?: never;
31
+ conversationToken?: never;
32
+ connectionType?: ElevenLabsConnectionType;
33
+ } | {
34
+ signedUrl: string;
35
+ agentId?: never;
36
+ conversationToken?: never;
37
+ connectionType?: 'websocket';
38
+ } | {
39
+ conversationToken: string;
40
+ agentId?: never;
41
+ signedUrl?: never;
42
+ connectionType?: 'webrtc';
43
+ };
44
+ export type ElevenLabsConfig = ElevenLabsSessionAuth & {
45
+ /** orb-ui expects a voice conversation, so text-only sessions are intentionally unsupported. */
46
+ textOnly?: false;
47
+ /** Allow @elevenlabs/client startSession options that orb-ui does not inspect. */
48
+ [key: string]: unknown;
49
+ };
50
+ export type ElevenLabsStartSessionOptions = ElevenLabsConfig & ElevenLabsCallbacks;
51
+ export interface ElevenLabsConversationClass {
52
+ startSession(options: ElevenLabsStartSessionOptions): Promise<ElevenLabsConversation>;
53
+ }
54
+ export interface ElevenLabsOrbAdapter extends OrbAdapter {
55
+ /** Start an ElevenLabs conversation. Called automatically by Orb on click. */
56
+ start(): Promise<void>;
57
+ /** Stop the current ElevenLabs conversation. Called automatically by Orb on click. */
58
+ stop(): Promise<void>;
59
+ }
60
+ /**
61
+ * Creates an OrbAdapter for ElevenLabs Conversational AI.
62
+ *
63
+ * Unlike createVapiAdapter, this adapter owns the session lifecycle because
64
+ * ElevenLabs requires callbacks to be injected at Conversation.startSession()
65
+ * time. Pass the returned adapter to Orb and Orb will call start()/stop()
66
+ * when the clickable theme is activated.
67
+ *
68
+ * @param ConversationClass - The Conversation class from @elevenlabs/client
69
+ * @param config - agentId / signedUrl + any other startSession options
70
+ *
71
+ * @example
72
+ * import { Conversation } from '@elevenlabs/client'
73
+ * import { Orb } from '@lofcz/orb-ui'
74
+ * import { createElevenLabsAdapter } from '@lofcz/orb-ui/adapters'
75
+ *
76
+ * const adapter = createElevenLabsAdapter(Conversation, {
77
+ * agentId: 'your-agent-id',
78
+ * })
79
+ *
80
+ * function App() {
81
+ * return <Orb adapter={adapter} theme="circle" aria-label="Start ElevenLabs assistant" />
82
+ * }
83
+ */
84
+ export declare function createElevenLabsAdapter(ConversationClass: ElevenLabsConversationClass, config: ElevenLabsConfig): ElevenLabsOrbAdapter;
85
+ export {};
@@ -0,0 +1,70 @@
1
+ import { OrbAdapter } from '../types.js';
2
+ import { OutputVolumeCalibrationSource, OutputVolumeSample } from '../audio-level.js';
3
+ export interface GeminiLiveInlineData {
4
+ data?: string;
5
+ mimeType?: string;
6
+ }
7
+ export interface GeminiLiveServerMessage {
8
+ setupComplete?: unknown;
9
+ serverContent?: {
10
+ modelTurn?: {
11
+ parts?: Array<{
12
+ inlineData?: GeminiLiveInlineData;
13
+ }>;
14
+ };
15
+ turnComplete?: boolean;
16
+ generationComplete?: boolean;
17
+ interrupted?: boolean;
18
+ waitingForInput?: boolean;
19
+ };
20
+ }
21
+ export interface GeminiLiveCallbacks {
22
+ onopen?: () => void;
23
+ onmessage: (message: GeminiLiveServerMessage) => void;
24
+ onerror?: (error: unknown) => void;
25
+ onclose?: (event: unknown) => void;
26
+ }
27
+ export interface GeminiLiveSession {
28
+ sendRealtimeInput(input: {
29
+ audio?: {
30
+ data: string;
31
+ mimeType: string;
32
+ };
33
+ audioStreamEnd?: boolean;
34
+ activityStart?: Record<string, never>;
35
+ activityEnd?: Record<string, never>;
36
+ }): void;
37
+ close(): void;
38
+ }
39
+ export interface GeminiLiveAdapterConfig {
40
+ /** Connects an official Google GenAI Live session using the supplied callbacks. */
41
+ connect(callbacks: GeminiLiveCallbacks): Promise<GeminiLiveSession>;
42
+ /** Defaults to `{ audio: true }`. */
43
+ mediaStreamConstraints?: MediaStreamConstraints;
44
+ /** Defaults to 16 kHz PCM input, as recommended by Gemini Live. */
45
+ inputSampleRate?: number;
46
+ /** Defaults to 0.04 normalized input volume. */
47
+ speechThreshold?: number;
48
+ /** Defaults to 500 ms before listening transitions to thinking. */
49
+ speechEndDelayMs?: number;
50
+ /** Defaults to client-side detection. Use `server` with Gemini automatic activity detection. */
51
+ activityDetection?: 'client' | 'server';
52
+ /** Runtime override for tests or custom browser wrappers. */
53
+ getUserMedia?: (constraints: MediaStreamConstraints) => Promise<MediaStream>;
54
+ /** Runtime override for tests or custom browser wrappers. */
55
+ createAudioContext?: () => AudioContext;
56
+ /** Optional live-tunable output shaping. A getter is read for every meter sample. */
57
+ outputVolumeCalibration?: OutputVolumeCalibrationSource;
58
+ /** Receives raw, shaped, and smoothed output levels for diagnostics. */
59
+ onOutputVolumeSample?: (sample: OutputVolumeSample) => void;
60
+ }
61
+ export interface GeminiLiveOrbAdapter extends OrbAdapter {
62
+ start(): Promise<void>;
63
+ stop(): Promise<void>;
64
+ }
65
+ /**
66
+ * Creates a managed browser-audio adapter for Gemini Live. The app owns token
67
+ * creation and the official GenAI client; orb-ui owns microphone streaming,
68
+ * PCM playback, volume metering, and normalized voice state.
69
+ */
70
+ export declare function createGeminiLiveAdapter(config: GeminiLiveAdapterConfig): GeminiLiveOrbAdapter;
@@ -0,0 +1,8 @@
1
+ export { createVapiAdapter } from './vapi/index.js';
2
+ export { createElevenLabsAdapter, type ElevenLabsCallbacks, type ElevenLabsConfig, type ElevenLabsConnectionType, type ElevenLabsConversation, type ElevenLabsConversationClass, type ElevenLabsMode, type ElevenLabsOrbAdapter, type ElevenLabsStartSessionOptions, type ElevenLabsStatus, } from './elevenlabs/index.js';
3
+ export { createLiveKitAdapter, type LiveKitAdapterConfig, type LiveKitConnectionDetails, type LiveKitOrbAdapter, type LiveKitResolvedTokenOptions, type LiveKitTokenOptions, type LiveKitTokenSource, } from './livekit/index.js';
4
+ export { createPipecatAdapter, type PipecatAdapterOptions, type PipecatClientLike, type PipecatOrbAdapter, type PipecatParticipantLike, type PipecatTracksLike, } from './pipecat/index.js';
5
+ export { createOpenAIRealtimeAdapter, type OpenAIRealtimeAdapterConfig, type OpenAIRealtimeClientSecret, type OpenAIRealtimeOrbAdapter, } from './openai-realtime/index.js';
6
+ export { createGeminiLiveAdapter, type GeminiLiveAdapterConfig, type GeminiLiveCallbacks, type GeminiLiveInlineData, type GeminiLiveOrbAdapter, type GeminiLiveServerMessage, type GeminiLiveSession, } from './gemini-live/index.js';
7
+ export { DEFAULT_OUTPUT_VOLUME_CALIBRATION, type OutputVolumeCalibration, type OutputVolumeCalibrationSource, type OutputVolumeSample, } from './audio-level.js';
8
+ export type { OrbAdapter, OrbSignal, OrbSignalListener, OrbState } from './types.js';
@@ -0,0 +1,49 @@
1
+ import { LiveKitOrbAdapter, LiveKitTokenOptions } from './index.js';
2
+ import { OutputVolumeCalibrationSource, OutputVolumeSample } from '../audio-level.js';
3
+ interface LiveKitBrowserAdapterBase extends Omit<LiveKitTokenOptions, 'agentName' | 'roomName'> {
4
+ /** Agent dispatched into the room. Required for LiveKit Cloud sandbox sessions. */
5
+ agentName?: LiveKitTokenOptions['agentName'];
6
+ /** Defaults to a fresh `orb-<uuid>` room name for every start. */
7
+ roomName?: LiveKitTokenOptions['roomName'];
8
+ /** LiveKit room.connect options passed through unchanged. */
9
+ connectOptions?: Record<string, unknown>;
10
+ /** Enable the local microphone after connecting. Defaults to true. */
11
+ enableMicrophone?: boolean;
12
+ /** Optional live-tunable output shaping. A getter is read for every meter sample. */
13
+ outputVolumeCalibration?: OutputVolumeCalibrationSource;
14
+ /** Receives raw, shaped, and smoothed output levels for diagnostics. */
15
+ onOutputVolumeSample?: (sample: OutputVolumeSample) => void;
16
+ }
17
+ export type LiveKitTokenEndpointOptions = Omit<RequestInit, 'body'>;
18
+ export interface LiveKitSandboxOptions {
19
+ /** Override LiveKit's default Cloud API base URL. */
20
+ baseUrl?: string;
21
+ }
22
+ export interface LiveKitEndpointAdapterConfig extends LiveKitBrowserAdapterBase {
23
+ /** LiveKit TokenSource endpoint returning `{ server_url, participant_token }`. */
24
+ tokenEndpoint: string;
25
+ /** Optional fetch settings such as authenticated request headers. */
26
+ tokenEndpointOptions?: LiveKitTokenEndpointOptions;
27
+ sandboxId?: never;
28
+ sandboxOptions?: never;
29
+ }
30
+ export interface LiveKitSandboxAdapterConfig extends LiveKitBrowserAdapterBase {
31
+ /** LiveKit Cloud sandbox token server ID. Sandbox mode is intended for testing only. */
32
+ sandboxId: string;
33
+ /** The agent to dispatch into the sandbox room. */
34
+ agentName: NonNullable<LiveKitTokenOptions['agentName']>;
35
+ /** Optional LiveKit sandbox host overrides. */
36
+ sandboxOptions?: LiveKitSandboxOptions;
37
+ tokenEndpoint?: never;
38
+ tokenEndpointOptions?: never;
39
+ }
40
+ export type LiveKitBrowserAdapterConfig = LiveKitEndpointAdapterConfig | LiveKitSandboxAdapterConfig;
41
+ /**
42
+ * Creates a managed LiveKit Agents adapter using the official browser SDK.
43
+ *
44
+ * This entrypoint owns the LiveKit Room, token source, microphone, playback,
45
+ * and audio analysers. Import the advanced factory from `@lofcz/orb-ui/adapters`
46
+ * only when your application already owns those pieces.
47
+ */
48
+ export declare function createLiveKitAdapter(config: LiveKitBrowserAdapterConfig): LiveKitOrbAdapter;
49
+ export type { LiveKitOrbAdapter } from './index.js';