@keyframelabs/elements 0.0.8 → 0.1.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.
package/README.md CHANGED
@@ -125,7 +125,7 @@ Currently, only the ElevenLabs agent emits emotion events.
125
125
  | `apiBaseUrl` | `string` | `'https://api.keyframelabs.com'` | Base URL for the Keyframe API. |
126
126
  | `videoFit` | `'cover' \| 'contain'` | `'cover'` | Video scaling mode (`object-fit`). |
127
127
  | `onStateChange` | `(status: EmbedStatus) => void` | — | Fired when connection status changes. |
128
- | `onAgentStateChange` | `(state: AgentState) => void` | — | Fired when agent state changes. |
128
+ | `onAgentStateChange` | `(state: AgentState) => void` | — | Fired when avatar playback state changes. Signaled by the GPU node via RPC, not the voice agent. |
129
129
  | `onDisconnect` | `() => void` | — | Fired when the session disconnects. |
130
130
  | `onError` | `(err: Error) => void` | — | Fired on fatal errors. |
131
131
 
@@ -142,7 +142,7 @@ Currently, only the ElevenLabs agent emits emotion events.
142
142
  | Property | Type | Description |
143
143
  | -------------- | ------------------ | -------------------------------------------------------------------------------------- |
144
144
  | `status` | `EmbedStatus` | Current connection status: `'connecting' \| 'connected' \| 'disconnected' \| 'error'`. |
145
- | `agentState` | `AgentState` | Current agent state: `'idle' \| 'listening' \| 'thinking' \| 'speaking'`. |
145
+ | `agentState` | `AgentState` | Avatar playback state: `'listening' \| 'speaking'`. Set by the GPU node, not the voice agent. |
146
146
  | `isMuted` | `boolean` | Whether the microphone is currently muted. |
147
147
  | `videoElement` | `HTMLVideoElement` | The underlying video element used for rendering. |
148
148
  | `audioElement` | `HTMLAudioElement` | The underlying audio element used for playback. |
@@ -1,4 +1,4 @@
1
- import { AgentState } from './agents';
1
+ import { AgentState } from '@keyframelabs/sdk';
2
2
  import { EmbedStatus, VideoFit, BaseCallbacks } from './types';
3
3
  export type { EmbedStatus, VideoFit } from './types';
4
4
  export interface PersonaEmbedOptions extends BaseCallbacks {
@@ -1,4 +1,4 @@
1
- import { AgentState } from './agents';
1
+ import { AgentState } from '@keyframelabs/sdk';
2
2
  import { EmbedStatus, VideoFit, VoiceAgentDetails, SessionDetails, BaseCallbacks } from './types';
3
3
  export interface PersonaViewOptions extends BaseCallbacks {
4
4
  /** Target container element */
package/dist/index.d.ts CHANGED
@@ -4,7 +4,8 @@ export { PersonaView } from './PersonaView';
4
4
  export type { PersonaViewOptions } from './PersonaView';
5
5
  export type { EmbedStatus, VideoFit, VoiceAgentDetails, SessionDetails, BaseCallbacks, } from './types';
6
6
  export { createAgent, GeminiLiveAgent, ElevenLabsAgent, CartesiaAgent, BaseAgent, AGENT_REGISTRY, getAgentInfo, } from './agents';
7
- export type { AgentType, AgentState, AgentConfig, AgentEventMap, Agent, AnyAgent, AgentTypeInfo, GeminiLiveConfig, ElevenLabsConfig, CartesiaConfig, } from './agents';
7
+ export type { AgentType, AgentConfig, AgentEventMap, Agent, AnyAgent, AgentTypeInfo, GeminiLiveConfig, ElevenLabsConfig, CartesiaConfig, } from './agents';
8
+ export type { AgentState } from '@keyframelabs/sdk';
8
9
  export { floatTo16BitPCM, resamplePcm, base64ToBytes, bytesToBase64, SAMPLE_RATE, createEventEmitter, } from './agents';
9
10
  export { ApiError as KeyframeApiError } from './ApiError';
10
11
  export type { ApiErrorPayload as KeyframeApiErrorPayload } from './ApiError';
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import { createClient as w } from "@keyframelabs/sdk";
1
+ import { createClient as f } from "@keyframelabs/sdk";
2
2
  const l = 24e3;
3
- function m(i) {
3
+ function g(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 g(i) {
9
+ function m(i) {
10
10
  let e = "";
11
11
  for (let t = 0; t < i.length; t++)
12
12
  e += String.fromCharCode(i[t]);
@@ -41,7 +41,7 @@ function E() {
41
41
  }
42
42
  };
43
43
  }
44
- function f(i) {
44
+ function w(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]));
@@ -113,7 +113,7 @@ class u {
113
113
  this.events.emit("closed", { code: e, reason: t });
114
114
  }
115
115
  }
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";
116
+ const A = "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
117
  class R extends u {
118
118
  agentName = "GeminiLive";
119
119
  async connect(e) {
@@ -122,7 +122,7 @@ class R 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 ?? C, n = (e.authType ?? "api_key") === "ephemeral_token" ? `${A}?access_token=${encodeURIComponent(e.apiKey)}` : `${k}?key=${encodeURIComponent(e.apiKey)}`;
125
+ const t = e.model ?? A, n = (e.authType ?? "api_key") === "ephemeral_token" ? `${k}?access_token=${encodeURIComponent(e.apiKey)}` : `${C}?key=${encodeURIComponent(e.apiKey)}`;
126
126
  return new Promise((a, r) => {
127
127
  this.ws = new WebSocket(n), this.ws.onopen = () => {
128
128
  const o = {
@@ -159,7 +159,7 @@ class R 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 = m(n.inlineData.data);
162
+ const a = g(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 R extends u {
181
181
  mediaChunks: [
182
182
  {
183
183
  mimeType: `audio/pcm;rate=${this.inputSampleRate}`,
184
- data: g(e)
184
+ data: m(e)
185
185
  }
186
186
  ]
187
187
  }
@@ -282,7 +282,7 @@ class S extends u {
282
282
  M.includes(o) && (this.events.emit("emotion", o), this.emotionEmittedForEventId = s);
283
283
  }
284
284
  }
285
- let n = m(t.audio_base_64);
285
+ let n = g(t.audio_base_64);
286
286
  this.outputSampleRate !== l && (n = c(n, this.outputSampleRate, l)), this.events.emit("audio", n);
287
287
  }
288
288
  handleUserTranscript(e) {
@@ -295,11 +295,11 @@ class S extends u {
295
295
  }
296
296
  handleAgentResponse(e) {
297
297
  const t = e.agent_response_event;
298
- t?.agent_response && this.events.emit("transcript", {
298
+ t?.agent_response && (this.events.emit("turnEnd", void 0), this.setState("listening"), this.events.emit("transcript", {
299
299
  role: "assistant",
300
300
  text: t.agent_response,
301
301
  isFinal: !0
302
- });
302
+ }));
303
303
  }
304
304
  handleInterruption(e) {
305
305
  const t = e.interruption_event;
@@ -310,7 +310,7 @@ class S extends u {
310
310
  return;
311
311
  let t = e;
312
312
  this.sourceInputSampleRate !== this.expectedInputSampleRate && (t = c(e, this.sourceInputSampleRate, this.expectedInputSampleRate)), this.ws.send(JSON.stringify({
313
- user_audio_chunk: g(t)
313
+ user_audio_chunk: m(t)
314
314
  }));
315
315
  }
316
316
  /**
@@ -425,7 +425,7 @@ class O extends u {
425
425
  handleMediaOutput(e) {
426
426
  if (!e.media?.payload) return;
427
427
  this._state !== "speaking" && (this.events.emit("turnStart", void 0), this.setState("speaking"));
428
- let t = m(e.media.payload);
428
+ let t = g(e.media.payload);
429
429
  this.cartesiaOutputRate !== l && (t = c(t, this.cartesiaOutputRate, l)), this.events.emit("audio", t);
430
430
  }
431
431
  handleClear() {
@@ -440,7 +440,7 @@ class O extends u {
440
440
  event: "media_input",
441
441
  stream_id: this.streamId,
442
442
  media: {
443
- payload: g(t)
443
+ payload: m(t)
444
444
  }
445
445
  }));
446
446
  }
@@ -574,7 +574,7 @@ class K {
574
574
  stream = null;
575
575
  abortController = null;
576
576
  _status = "disconnected";
577
- _agentState = "idle";
577
+ _agentState = "listening";
578
578
  _isMuted = !1;
579
579
  mounted = !0;
580
580
  constructor(e) {
@@ -666,7 +666,7 @@ class K {
666
666
  return t.json();
667
667
  }
668
668
  async initSession(e) {
669
- this.session = w({
669
+ this.session = f({
670
670
  serverUrl: e.session_details.server_url,
671
671
  participantToken: e.session_details.participant_token,
672
672
  agentIdentity: e.session_details.agent_identity,
@@ -680,13 +680,18 @@ class K {
680
680
  onStateChange: (t) => {
681
681
  this.mounted && t === "disconnected" && (this.setStatus("disconnected"), this.callbacks.onDisconnect?.());
682
682
  },
683
+ onAgentStateChange: (t) => {
684
+ this.mounted && this.setAgentState(t);
685
+ },
683
686
  onError: (t) => {
684
687
  this.mounted && this.callbacks.onError?.(t);
685
688
  },
686
689
  onClose: () => {
687
690
  this.mounted && this.callbacks.onDisconnect?.();
688
691
  }
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", () => {
692
+ }), this.agent = y(e.voice_agent_details.type), this.agent.on("audio", (t) => this.session?.sendAudio(t)), this.agent.on("turnEnd", () => this.session?.endAudioTurn()), this.agent.on("interrupted", () => {
693
+ this.session?.endAudioTurn(), this.session?.interrupt();
694
+ }), this.agent.on("closed", () => {
690
695
  this.mounted && this.callbacks.onDisconnect?.();
691
696
  }), this.agent instanceof S && this.agent.on("emotion", (t) => this.session?.setEmotion(t)), await this.session.connect();
692
697
  }
@@ -697,7 +702,7 @@ class K {
697
702
  const e = this.audioContext.createMediaStreamSource(this.stream);
698
703
  this.processor = this.audioContext.createScriptProcessor(4096, 1, 1), this.processor.onaudioprocess = (t) => {
699
704
  if (!this._isMuted) {
700
- const s = f(t.inputBuffer.getChannelData(0));
705
+ const s = w(t.inputBuffer.getChannelData(0));
701
706
  this.agent?.sendAudio(s);
702
707
  }
703
708
  }, e.connect(this.processor), this.processor.connect(this.audioContext.destination);
@@ -742,7 +747,7 @@ class B {
742
747
  processor = null;
743
748
  stream = null;
744
749
  _status = "disconnected";
745
- _agentState = "idle";
750
+ _agentState = "listening";
746
751
  _isMuted = !1;
747
752
  mounted = !0;
748
753
  constructor(e) {
@@ -801,7 +806,7 @@ class B {
801
806
  this._agentState !== e && (this._agentState = e, this.callbacks.onAgentStateChange?.(e));
802
807
  }
803
808
  async initSession() {
804
- this.session = w({
809
+ this.session = f({
805
810
  serverUrl: this.sessionDetails.server_url,
806
811
  participantToken: this.sessionDetails.participant_token,
807
812
  agentIdentity: this.sessionDetails.agent_identity,
@@ -815,13 +820,18 @@ class B {
815
820
  onStateChange: (e) => {
816
821
  this.mounted && e === "disconnected" && (this.setStatus("disconnected"), this.callbacks.onDisconnect?.());
817
822
  },
823
+ onAgentStateChange: (e) => {
824
+ this.mounted && this.setAgentState(e);
825
+ },
818
826
  onError: (e) => {
819
827
  this.mounted && this.callbacks.onError?.(e);
820
828
  },
821
829
  onClose: () => {
822
830
  this.mounted && this.callbacks.onDisconnect?.();
823
831
  }
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", () => {
832
+ }), this.agent = y(this.voiceAgentDetails.type), this.agent.on("audio", (e) => this.session?.sendAudio(e)), this.agent.on("turnEnd", () => this.session?.endAudioTurn()), this.agent.on("interrupted", () => {
833
+ this.session?.endAudioTurn(), this.session?.interrupt();
834
+ }), this.agent.on("closed", () => {
825
835
  this.mounted && this.callbacks.onDisconnect?.();
826
836
  }), this.agent instanceof S && this.agent.on("emotion", (e) => this.session?.setEmotion(e)), await this.session.connect();
827
837
  }
@@ -832,7 +842,7 @@ class B {
832
842
  const e = this.audioContext.createMediaStreamSource(this.stream);
833
843
  this.processor = this.audioContext.createScriptProcessor(4096, 1, 1), this.processor.onaudioprocess = (t) => {
834
844
  if (!this._isMuted) {
835
- const s = f(t.inputBuffer.getChannelData(0));
845
+ const s = w(t.inputBuffer.getChannelData(0));
836
846
  this.agent?.sendAudio(s);
837
847
  }
838
848
  }, e.connect(this.processor), this.processor.connect(this.audioContext.destination);
@@ -871,11 +881,11 @@ export {
871
881
  K as PersonaEmbed,
872
882
  B as PersonaView,
873
883
  l as SAMPLE_RATE,
874
- m as base64ToBytes,
875
- g as bytesToBase64,
884
+ g as base64ToBytes,
885
+ m as bytesToBase64,
876
886
  y as createAgent,
877
887
  E as createEventEmitter,
878
- f as floatTo16BitPCM,
888
+ w as floatTo16BitPCM,
879
889
  F as getAgentInfo,
880
890
  c as resamplePcm
881
891
  };
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { AgentType, AgentState } from './agents';
1
+ import { AgentType } from './agents';
2
+ import { AgentState } from '@keyframelabs/sdk';
2
3
  export type EmbedStatus = 'connecting' | 'connected' | 'error' | 'disconnected';
3
4
  export type VideoFit = 'cover' | 'contain';
4
5
  export type VoiceAgentDetails = {
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.0.8",
7
+ "version": "0.1.0",
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.6"
22
+ "@keyframelabs/sdk": "0.1.8"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/node": "^25.0.9",