@keyframelabs/elements 0.0.6 → 0.0.8

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.
package/README.md CHANGED
@@ -71,12 +71,47 @@ view.disconnect();
71
71
 
72
72
  ## Supported agents and real-time LLMs
73
73
 
74
- Supports ElevenLabs Agents, Cartesia Line, Gemini Live, and Vapi.
74
+ Supports Cartesia, ElevenLabs, Vapi, Gemini Live (closed alpha), OpenAI Realtime (closed alpha).
75
75
 
76
76
  For `PersonaEmbed`, this is determined by the values you set in the Keyframe platform dashboard.
77
77
 
78
78
  For `PersonaView`, this is determined by `voiceAgentDetails`.
79
79
 
80
+ ## Emotion Controls
81
+
82
+ The avatar can display emotional expressions (`neutral`, `angry`, `sad`, `happy`) that affect its facial expression and demeanor.
83
+
84
+ ### Automatic Emotion Detection (ElevenLabs)
85
+
86
+ When using ElevenLabs as the voice agent, emotions are automatically detected from the agent's speech. The ElevenLabs agent parses emotion tags from audio alignment data (e.g., `[angry]`, `[happy]`) and the avatar expression updates in real-time.
87
+
88
+ This requires no additional configuration—just configure your ElevenLabs agent to include emotion tags in its responses.
89
+
90
+ ### Manual Emotion Control
91
+
92
+ For other agents or custom emotion logic, you can access the underlying session to set emotions manually:
93
+
94
+ ```typescript
95
+ // Access the underlying SDK session for manual control
96
+ // (Available when using @keyframelabs/sdk directly)
97
+ import { createClient } from '@keyframelabs/sdk';
98
+
99
+ const session = createClient({ ... });
100
+ await session.setEmotion('happy');
101
+ ```
102
+
103
+ ### Agent Events
104
+
105
+ The `emotion` event is emitted when an agent detects an emotion change:
106
+
107
+ ```typescript
108
+ agent.on('emotion', (emotion) => {
109
+ console.log('Emotion detected:', emotion); // 'neutral' | 'angry' | 'sad' | 'happy'
110
+ });
111
+ ```
112
+
113
+ Currently, only the ElevenLabs agent emits emotion events.
114
+
80
115
  ## API
81
116
 
82
117
  ### `PersonaEmbed`
@@ -145,11 +180,13 @@ type SessionDetails = {
145
180
  };
146
181
 
147
182
  type VoiceAgentDetails = {
148
- type: 'gemini' | 'elevenlabs' | 'cartesia' | 'vapi';
183
+ type: 'cartesia' | 'elevenlabs' | 'vapi' | 'gemini' | 'openai';
149
184
  token?: string; // For gemini, cartesia
150
185
  agent_id?: string; // For elevenlabs, cartesia
151
186
  signed_url?: string; // For elevenlabs, vapi
152
187
  };
188
+
189
+ type Emotion = 'neutral' | 'angry' | 'sad' | 'happy';
153
190
  ```
154
191
 
155
192
  ## License
@@ -20,6 +20,7 @@ export declare class ElevenLabsAgent extends BaseAgent {
20
20
  private sourceInputSampleRate;
21
21
  private initialized;
22
22
  private lastInterruptId;
23
+ private emotionEmittedForEventId;
23
24
  connect(config: ElevenLabsConfig): Promise<void>;
24
25
  protected handleParsedMessage(message: unknown): void;
25
26
  private handleInitMetadata;
@@ -9,7 +9,7 @@ import { VapiAgent, VapiConfig } from './vapi';
9
9
  * various voice AI backends to the Persona SDK.
10
10
  */
11
11
  export { BaseAgent, DEFAULT_INPUT_SAMPLE_RATE } from './base';
12
- export type { Agent, AgentConfig, AgentEventMap, AgentState } from './types';
12
+ export type { Agent, AgentConfig, AgentEventMap, AgentState, Emotion } from './types';
13
13
  export { GeminiLiveAgent, type GeminiLiveConfig };
14
14
  export { ElevenLabsAgent, type ElevenLabsConfig };
15
15
  export { CartesiaAgent, type CartesiaConfig };
@@ -8,6 +8,8 @@
8
8
  */
9
9
  /** Agent state for UI */
10
10
  export type AgentState = 'idle' | 'listening' | 'thinking' | 'speaking';
11
+ /** Emotion states for avatar expression */
12
+ export type Emotion = 'neutral' | 'angry' | 'sad' | 'happy';
11
13
  /** Agent configuration */
12
14
  export interface AgentConfig {
13
15
  /** System prompt for the agent */
@@ -37,6 +39,8 @@ export interface AgentEventMap {
37
39
  text: string;
38
40
  isFinal: boolean;
39
41
  };
42
+ /** Emotion change (currently only supported by ElevenLabs agent) */
43
+ emotion: Emotion;
40
44
  /** Agent connection closed (unexpected disconnect) */
41
45
  closed: {
42
46
  code?: number;
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import { createClient as v } from "@keyframelabs/sdk";
2
- const h = 24e3;
3
- function g(i) {
1
+ import { createClient as w } from "@keyframelabs/sdk";
2
+ const l = 24e3;
3
+ function m(i) {
4
4
  const e = atob(i), t = new Uint8Array(e.length);
5
5
  for (let s = 0; s < e.length; s++)
6
6
  t[s] = e.charCodeAt(s);
7
7
  return t;
8
8
  }
9
- function m(i) {
9
+ function g(i) {
10
10
  let e = "";
11
11
  for (let t = 0; t < i.length; t++)
12
12
  e += String.fromCharCode(i[t]);
@@ -15,16 +15,16 @@ function m(i) {
15
15
  function c(i, e, t) {
16
16
  if (e === t)
17
17
  return i;
18
- const s = new Int16Array(i.buffer, i.byteOffset, i.length / 2), n = e / t, a = Math.floor(s.length / n), o = new Int16Array(a);
19
- for (let r = 0; r < a; r++) {
20
- const S = r * n, p = Math.floor(S), f = Math.min(p + 1, s.length - 1), _ = S - p;
21
- o[r] = Math.round(
22
- s[p] * (1 - _) + s[f] * _
18
+ const s = new Int16Array(i.buffer, i.byteOffset, i.length / 2), n = e / t, a = Math.floor(s.length / n), r = new Int16Array(a);
19
+ for (let o = 0; o < a; o++) {
20
+ const _ = o * n, p = Math.floor(_), b = Math.min(p + 1, s.length - 1), v = _ - p;
21
+ r[o] = Math.round(
22
+ s[p] * (1 - v) + s[b] * v
23
23
  );
24
24
  }
25
- return new Uint8Array(o.buffer);
25
+ return new Uint8Array(r.buffer);
26
26
  }
27
- function b() {
27
+ function E() {
28
28
  const i = /* @__PURE__ */ new Map();
29
29
  return {
30
30
  on(e, t) {
@@ -41,7 +41,7 @@ function b() {
41
41
  }
42
42
  };
43
43
  }
44
- function w(i) {
44
+ function f(i) {
45
45
  const e = new Int16Array(i.length);
46
46
  for (let t = 0; t < i.length; t++) {
47
47
  const s = Math.max(-1, Math.min(1, i[t]));
@@ -53,7 +53,7 @@ const I = 16e3;
53
53
  class u {
54
54
  ws = null;
55
55
  _state = "idle";
56
- events = b();
56
+ events = E();
57
57
  inputSampleRate = I;
58
58
  /** Current agent state */
59
59
  get state() {
@@ -113,8 +113,8 @@ class u {
113
113
  this.events.emit("closed", { code: e, reason: t });
114
114
  }
115
115
  }
116
- const E = "gemini-2.5-flash-native-audio-preview-12-2025", C = "wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent", k = "wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContentConstrained";
117
- class A extends u {
116
+ const C = "gemini-2.5-flash-native-audio-preview-12-2025", k = "wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent", A = "wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContentConstrained";
117
+ class R extends u {
118
118
  agentName = "GeminiLive";
119
119
  async connect(e) {
120
120
  if (this.ws)
@@ -122,10 +122,10 @@ class A extends u {
122
122
  if (!e.apiKey)
123
123
  throw new Error("Gemini API key is required");
124
124
  e.inputSampleRate && (this.inputSampleRate = e.inputSampleRate);
125
- const t = e.model ?? E, n = (e.authType ?? "api_key") === "ephemeral_token" ? `${k}?access_token=${encodeURIComponent(e.apiKey)}` : `${C}?key=${encodeURIComponent(e.apiKey)}`;
126
- return new Promise((a, o) => {
125
+ const t = e.model ?? C, n = (e.authType ?? "api_key") === "ephemeral_token" ? `${A}?access_token=${encodeURIComponent(e.apiKey)}` : `${k}?key=${encodeURIComponent(e.apiKey)}`;
126
+ return new Promise((a, r) => {
127
127
  this.ws = new WebSocket(n), this.ws.onopen = () => {
128
- const r = {
128
+ const o = {
129
129
  setup: {
130
130
  model: `models/${t}`,
131
131
  generationConfig: {
@@ -134,13 +134,13 @@ class A extends u {
134
134
  systemInstruction: e.systemPrompt ? { parts: [{ text: e.systemPrompt }] } : void 0
135
135
  }
136
136
  };
137
- this.ws.send(JSON.stringify(r)), this.setState("listening"), a();
137
+ this.ws.send(JSON.stringify(o)), this.setState("listening"), a();
138
138
  }, this.ws.onerror = () => {
139
- o(new Error("Failed to connect to Gemini Live"));
140
- }, this.ws.onclose = (r) => {
141
- this.ws = null, this.setState("idle"), this.emitClosed(r.code, r.reason);
142
- }, this.ws.onmessage = (r) => {
143
- this.handleMessage(r.data);
139
+ r(new Error("Failed to connect to Gemini Live"));
140
+ }, this.ws.onclose = (o) => {
141
+ this.ws = null, this.setState("idle"), this.emitClosed(o.code, o.reason);
142
+ }, this.ws.onmessage = (o) => {
143
+ this.handleMessage(o.data);
144
144
  };
145
145
  });
146
146
  }
@@ -159,7 +159,7 @@ class A extends u {
159
159
  this._state !== "speaking" && (this.events.emit("turnStart", void 0), this.setState("speaking"));
160
160
  for (const n of s.modelTurn.parts) {
161
161
  if (n.inlineData?.data) {
162
- const a = g(n.inlineData.data);
162
+ const a = m(n.inlineData.data);
163
163
  this.events.emit("audio", a);
164
164
  }
165
165
  n.text && this.events.emit("transcript", {
@@ -181,7 +181,7 @@ class A extends u {
181
181
  mediaChunks: [
182
182
  {
183
183
  mimeType: `audio/pcm;rate=${this.inputSampleRate}`,
184
- data: m(e)
184
+ data: g(e)
185
185
  }
186
186
  ]
187
187
  }
@@ -189,8 +189,8 @@ class A extends u {
189
189
  this.ws.send(JSON.stringify(t));
190
190
  }
191
191
  }
192
- const R = "wss://api.elevenlabs.io/v1/convai/conversation";
193
- class M extends u {
192
+ const M = ["neutral", "angry", "sad", "happy"], x = "wss://api.elevenlabs.io/v1/convai/conversation";
193
+ class S extends u {
194
194
  agentName = "ElevenLabs";
195
195
  outputSampleRate = 24e3;
196
196
  // Default, updated from metadata
@@ -202,6 +202,8 @@ class M extends u {
202
202
  // True after conversation_initiation_metadata received
203
203
  lastInterruptId = 0;
204
204
  // Track interruptions to filter stale audio
205
+ emotionEmittedForEventId = -1;
206
+ // Track which turn's emotion we've already emitted
205
207
  async connect(e) {
206
208
  if (this.ws)
207
209
  throw new Error("Already connected");
@@ -209,7 +211,7 @@ class M extends u {
209
211
  throw new Error("ElevenLabs agent ID or signed URL is required");
210
212
  e.inputSampleRate && (this.sourceInputSampleRate = e.inputSampleRate);
211
213
  let t;
212
- return e.signedUrl ? t = e.signedUrl : (t = `${R}?agent_id=${e.agentId}`, e.apiKey && (t += `&xi-api-key=${e.apiKey}`)), new Promise((s, n) => {
214
+ return e.signedUrl ? t = e.signedUrl : (t = `${x}?agent_id=${e.agentId}`, e.apiKey && (t += `&xi-api-key=${e.apiKey}`)), new Promise((s, n) => {
213
215
  this.ws = new WebSocket(t), this.ws.onopen = () => {
214
216
  this.setState("listening"), s();
215
217
  }, this.ws.onerror = () => {
@@ -269,19 +271,19 @@ class M extends u {
269
271
  }
270
272
  handleAudio(e) {
271
273
  const t = e.audio_event;
272
- if (!t?.audio_base_64 || (t.event_id ?? 0) <= this.lastInterruptId)
274
+ if (!t?.audio_base_64) return;
275
+ const s = t.event_id ?? 0;
276
+ if (s <= this.lastInterruptId)
273
277
  return;
274
- this._state !== "speaking" && (this.events.emit("turnStart", void 0), this.setState("speaking"));
275
- let n = g(t.audio_base_64);
276
- this.outputSampleRate !== h && (n = c(n, this.outputSampleRate, h));
277
- const a = 4800;
278
- if (n.length <= a)
279
- this.events.emit("audio", n);
280
- else
281
- for (let o = 0; o < n.length; o += a) {
282
- const r = n.slice(o, Math.min(o + a, n.length));
283
- this.events.emit("audio", r);
278
+ if (this._state !== "speaking" && (this.events.emit("turnStart", void 0), this.setState("speaking")), this.emotionEmittedForEventId !== s && t.alignment?.chars) {
279
+ const r = t.alignment.chars.join("").match(/\[(\w+)\]/);
280
+ if (r) {
281
+ const o = r[1].toLowerCase();
282
+ M.includes(o) && (this.events.emit("emotion", o), this.emotionEmittedForEventId = s);
284
283
  }
284
+ }
285
+ let n = m(t.audio_base_64);
286
+ this.outputSampleRate !== l && (n = c(n, this.outputSampleRate, l)), this.events.emit("audio", n);
285
287
  }
286
288
  handleUserTranscript(e) {
287
289
  const t = e.user_transcription_event;
@@ -308,7 +310,7 @@ class M extends u {
308
310
  return;
309
311
  let t = e;
310
312
  this.sourceInputSampleRate !== this.expectedInputSampleRate && (t = c(e, this.sourceInputSampleRate, this.expectedInputSampleRate)), this.ws.send(JSON.stringify({
311
- user_audio_chunk: m(t)
313
+ user_audio_chunk: g(t)
312
314
  }));
313
315
  }
314
316
  /**
@@ -341,8 +343,8 @@ class M extends u {
341
343
  this.initialized = !1, this.lastInterruptId = 0, super.close();
342
344
  }
343
345
  }
344
- const x = "wss://api.cartesia.ai/agents/stream", P = "2025-04-16";
345
- class T extends u {
346
+ const P = "wss://api.cartesia.ai/agents/stream", T = "2025-04-16";
347
+ class O extends u {
346
348
  agentName = "Cartesia";
347
349
  // Audio configuration
348
350
  cartesiaInputFormat = "pcm_16000";
@@ -361,7 +363,7 @@ class T extends u {
361
363
  if (!e.apiKey)
362
364
  throw new Error("Cartesia API Key is required");
363
365
  e.inputSampleRate && (this.inputSampleRate = e.inputSampleRate), this.inputSampleRate === 16e3 ? this.cartesiaInputFormat = "pcm_16000" : this.inputSampleRate === 24e3 ? this.cartesiaInputFormat = "pcm_24000" : this.inputSampleRate === 44100 ? this.cartesiaInputFormat = "pcm_44100" : this.cartesiaInputFormat = "pcm_16000";
364
- const t = `${x}/${e.agentId}?api_key=${e.apiKey}&cartesia_version=${P}`;
366
+ const t = `${P}/${e.agentId}?api_key=${e.apiKey}&cartesia_version=${T}`;
365
367
  return new Promise((s, n) => {
366
368
  this.ws = new WebSocket(t), this.ws.onopen = () => {
367
369
  this.sendStartEvent(), this.startHeartbeat(), s();
@@ -423,8 +425,8 @@ class T extends u {
423
425
  handleMediaOutput(e) {
424
426
  if (!e.media?.payload) return;
425
427
  this._state !== "speaking" && (this.events.emit("turnStart", void 0), this.setState("speaking"));
426
- let t = g(e.media.payload);
427
- this.cartesiaOutputRate !== h && (t = c(t, this.cartesiaOutputRate, h)), this.events.emit("audio", t);
428
+ let t = m(e.media.payload);
429
+ this.cartesiaOutputRate !== l && (t = c(t, this.cartesiaOutputRate, l)), this.events.emit("audio", t);
428
430
  }
429
431
  handleClear() {
430
432
  this.events.emit("interrupted", void 0), this.setState("listening");
@@ -438,7 +440,7 @@ class T extends u {
438
440
  event: "media_input",
439
441
  stream_id: this.streamId,
440
442
  media: {
441
- payload: m(t)
443
+ payload: g(t)
442
444
  }
443
445
  }));
444
446
  }
@@ -446,7 +448,7 @@ class T extends u {
446
448
  this.stopHeartbeat(), this.isReady = !1, this.streamId = null, super.close();
447
449
  }
448
450
  }
449
- class O extends u {
451
+ class N extends u {
450
452
  agentName = "Vapi";
451
453
  // Audio configuration - Vapi uses 16kHz PCM by default
452
454
  vapiSampleRate = 16e3;
@@ -473,7 +475,7 @@ class O extends u {
473
475
  */
474
476
  handleBinaryAudio(e) {
475
477
  this._state !== "speaking" && (this.events.emit("turnStart", void 0), this.setState("speaking"));
476
- const t = new Uint8Array(e), s = this.vapiSampleRate !== h ? c(t, this.vapiSampleRate, h) : t;
478
+ const t = new Uint8Array(e), s = this.vapiSampleRate !== l ? c(t, this.vapiSampleRate, l) : t;
477
479
  this.events.emit("audio", s);
478
480
  }
479
481
  handleParsedMessage(e) {
@@ -525,7 +527,7 @@ class O extends u {
525
527
  this.hangup(), super.close();
526
528
  }
527
529
  }
528
- const N = [
530
+ const U = [
529
531
  { id: "gemini", name: "Gemini Live", description: "Google Gemini Live API" },
530
532
  { id: "elevenlabs", name: "ElevenLabs", description: "ElevenLabs Conversational AI" },
531
533
  { id: "cartesia", name: "Cartesia", description: "Cartesia Agents API" },
@@ -534,21 +536,21 @@ const N = [
534
536
  function y(i) {
535
537
  switch (i) {
536
538
  case "gemini":
537
- return new A();
539
+ return new R();
538
540
  case "elevenlabs":
539
- return new M();
541
+ return new S();
540
542
  case "cartesia":
541
- return new T();
542
- case "vapi":
543
543
  return new O();
544
+ case "vapi":
545
+ return new N();
544
546
  default:
545
547
  throw new Error(`Unknown agent type: ${i}`);
546
548
  }
547
549
  }
548
- function L(i) {
549
- return N.find((e) => e.id === i);
550
+ function F(i) {
551
+ return U.find((e) => e.id === i);
550
552
  }
551
- class U extends Error {
553
+ class D extends Error {
552
554
  status;
553
555
  payload;
554
556
  url;
@@ -556,8 +558,8 @@ class U extends Error {
556
558
  super(e.message), this.name = "ApiError", this.status = e.status, this.payload = e.payload, this.url = e.url;
557
559
  }
558
560
  }
559
- const l = /* @__PURE__ */ new Set();
560
- class F {
561
+ const h = /* @__PURE__ */ new Set();
562
+ class K {
561
563
  apiBaseUrl;
562
564
  publishableKey;
563
565
  callbacks;
@@ -601,31 +603,31 @@ class F {
601
603
  }
602
604
  /** Connect to the embed session */
603
605
  async connect() {
604
- if (l.has(this.publishableKey)) {
606
+ if (h.has(this.publishableKey)) {
605
607
  console.log("[PersonaEmbed] Connection already in progress, skipping");
606
608
  return;
607
609
  }
608
- l.add(this.publishableKey), this.mounted = !0, this.abortController = new AbortController(), this.setStatus("connecting");
610
+ h.add(this.publishableKey), this.mounted = !0, this.abortController = new AbortController(), this.setStatus("connecting");
609
611
  try {
610
612
  const e = await this.fetchSession(this.abortController.signal);
611
613
  if (!this.mounted) {
612
- l.delete(this.publishableKey);
614
+ h.delete(this.publishableKey);
613
615
  return;
614
616
  }
615
617
  if (await this.initSession(e), await this.initMicrophone(), await this.connectAgent(e.voice_agent_details), !this.mounted) {
616
- this.cleanup(), l.delete(this.publishableKey);
618
+ this.cleanup(), h.delete(this.publishableKey);
617
619
  return;
618
620
  }
619
621
  this.setStatus("connected");
620
622
  } catch (e) {
621
- if (l.delete(this.publishableKey), e instanceof Error && e.name === "AbortError")
623
+ if (h.delete(this.publishableKey), e instanceof Error && e.name === "AbortError")
622
624
  return;
623
625
  console.error("[PersonaEmbed]", e), this.mounted && (this.setStatus("error"), this.callbacks.onError?.(e));
624
626
  }
625
627
  }
626
628
  /** Disconnect and cleanup */
627
629
  disconnect() {
628
- this.mounted = !1, this.abortController?.abort(), this.abortController = null, l.delete(this.publishableKey), this.cleanup(), this.setStatus("disconnected");
630
+ this.mounted = !1, this.abortController?.abort(), this.abortController = null, h.delete(this.publishableKey), this.cleanup(), this.setStatus("disconnected");
629
631
  }
630
632
  /** Toggle microphone mute */
631
633
  toggleMute() {
@@ -650,7 +652,7 @@ class F {
650
652
  s = await t.json();
651
653
  } catch {
652
654
  }
653
- throw new U({
655
+ throw new D({
654
656
  message: s?.message ?? "create_session failed",
655
657
  status: t.status,
656
658
  payload: s,
@@ -664,7 +666,7 @@ class F {
664
666
  return t.json();
665
667
  }
666
668
  async initSession(e) {
667
- this.session = v({
669
+ this.session = w({
668
670
  serverUrl: e.session_details.server_url,
669
671
  participantToken: e.session_details.participant_token,
670
672
  agentIdentity: e.session_details.agent_identity,
@@ -686,7 +688,7 @@ class F {
686
688
  }
687
689
  }), this.agent = y(e.voice_agent_details.type), this.agent.on("audio", (t) => this.session?.sendAudio(t)), this.agent.on("interrupted", () => this.session?.interrupt()), this.agent.on("stateChange", (t) => this.setAgentState(t)), this.agent.on("closed", () => {
688
690
  this.mounted && this.callbacks.onDisconnect?.();
689
- }), await this.session.connect();
691
+ }), this.agent instanceof S && this.agent.on("emotion", (t) => this.session?.setEmotion(t)), await this.session.connect();
690
692
  }
691
693
  async initMicrophone() {
692
694
  this.stream = await navigator.mediaDevices.getUserMedia({
@@ -695,7 +697,7 @@ class F {
695
697
  const e = this.audioContext.createMediaStreamSource(this.stream);
696
698
  this.processor = this.audioContext.createScriptProcessor(4096, 1, 1), this.processor.onaudioprocess = (t) => {
697
699
  if (!this._isMuted) {
698
- const s = w(t.inputBuffer.getChannelData(0));
700
+ const s = f(t.inputBuffer.getChannelData(0));
699
701
  this.agent?.sendAudio(s);
700
702
  }
701
703
  }, e.connect(this.processor), this.processor.connect(this.audioContext.destination);
@@ -725,7 +727,7 @@ class F {
725
727
  }
726
728
  }
727
729
  const d = /* @__PURE__ */ new Set();
728
- class K {
730
+ class B {
729
731
  voiceAgentDetails;
730
732
  sessionDetails;
731
733
  callbacks;
@@ -799,7 +801,7 @@ class K {
799
801
  this._agentState !== e && (this._agentState = e, this.callbacks.onAgentStateChange?.(e));
800
802
  }
801
803
  async initSession() {
802
- this.session = v({
804
+ this.session = w({
803
805
  serverUrl: this.sessionDetails.server_url,
804
806
  participantToken: this.sessionDetails.participant_token,
805
807
  agentIdentity: this.sessionDetails.agent_identity,
@@ -821,7 +823,7 @@ class K {
821
823
  }
822
824
  }), this.agent = y(this.voiceAgentDetails.type), this.agent.on("audio", (e) => this.session?.sendAudio(e)), this.agent.on("interrupted", () => this.session?.interrupt()), this.agent.on("stateChange", (e) => this.setAgentState(e)), this.agent.on("closed", () => {
823
825
  this.mounted && this.callbacks.onDisconnect?.();
824
- }), await this.session.connect();
826
+ }), this.agent instanceof S && this.agent.on("emotion", (e) => this.session?.setEmotion(e)), await this.session.connect();
825
827
  }
826
828
  async initMicrophone() {
827
829
  this.stream = await navigator.mediaDevices.getUserMedia({
@@ -830,7 +832,7 @@ class K {
830
832
  const e = this.audioContext.createMediaStreamSource(this.stream);
831
833
  this.processor = this.audioContext.createScriptProcessor(4096, 1, 1), this.processor.onaudioprocess = (t) => {
832
834
  if (!this._isMuted) {
833
- const s = w(t.inputBuffer.getChannelData(0));
835
+ const s = f(t.inputBuffer.getChannelData(0));
834
836
  this.agent?.sendAudio(s);
835
837
  }
836
838
  }, e.connect(this.processor), this.processor.connect(this.audioContext.destination);
@@ -860,20 +862,20 @@ class K {
860
862
  }
861
863
  }
862
864
  export {
863
- N as AGENT_REGISTRY,
865
+ U as AGENT_REGISTRY,
864
866
  u as BaseAgent,
865
- T as CartesiaAgent,
866
- M as ElevenLabsAgent,
867
- A as GeminiLiveAgent,
868
- U as KeyframeApiError,
869
- F as PersonaEmbed,
870
- K as PersonaView,
871
- h as SAMPLE_RATE,
872
- g as base64ToBytes,
873
- m as bytesToBase64,
867
+ O as CartesiaAgent,
868
+ S as ElevenLabsAgent,
869
+ R as GeminiLiveAgent,
870
+ D as KeyframeApiError,
871
+ K as PersonaEmbed,
872
+ B as PersonaView,
873
+ l as SAMPLE_RATE,
874
+ m as base64ToBytes,
875
+ g as bytesToBase64,
874
876
  y as createAgent,
875
- b as createEventEmitter,
876
- w as floatTo16BitPCM,
877
- L as getAgentInfo,
877
+ E as createEventEmitter,
878
+ f as floatTo16BitPCM,
879
+ F as getAgentInfo,
878
880
  c as resamplePcm
879
881
  };
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.0.6",
7
+ "version": "0.0.8",
8
8
  "type": "module",
9
9
  "main": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "sideEffects": false,
21
21
  "dependencies": {
22
- "@keyframelabs/sdk": "0.1.5"
22
+ "@keyframelabs/sdk": "0.1.6"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/node": "^25.0.9",