@absolutejs/voice 0.0.22-beta.91 → 0.0.22-beta.92

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.
@@ -3063,11 +3063,26 @@ var DEFAULT_INTERRUPT_THRESHOLD = 0.08;
3063
3063
  var shouldInterruptForLevel = (level, options = {}) => (options.enabled ?? true) && level >= (options.interruptThreshold ?? DEFAULT_INTERRUPT_THRESHOLD);
3064
3064
  var bindVoiceBargeIn = (controller, player, options = {}) => {
3065
3065
  let lastPartial = controller.partial;
3066
- const interruptIfPlaying = () => {
3066
+ const interruptIfPlaying = (reason) => {
3067
3067
  if (!player.isPlaying || options.enabled === false) {
3068
+ options.monitor?.recordSkipped({
3069
+ reason,
3070
+ sessionId: controller.sessionId
3071
+ });
3068
3072
  return;
3069
3073
  }
3070
- player.interrupt();
3074
+ options.monitor?.recordRequested({
3075
+ reason,
3076
+ sessionId: controller.sessionId
3077
+ });
3078
+ player.interrupt().then(() => {
3079
+ options.monitor?.recordStopped({
3080
+ latencyMs: player.lastInterruptLatencyMs,
3081
+ playbackStopLatencyMs: player.lastPlaybackStopLatencyMs,
3082
+ reason,
3083
+ sessionId: controller.sessionId
3084
+ });
3085
+ });
3071
3086
  };
3072
3087
  const unsubscribe = controller.subscribe(() => {
3073
3088
  if (options.interruptOnPartial === false) {
@@ -3075,7 +3090,7 @@ var bindVoiceBargeIn = (controller, player, options = {}) => {
3075
3090
  return;
3076
3091
  }
3077
3092
  if (!lastPartial && controller.partial) {
3078
- interruptIfPlaying();
3093
+ interruptIfPlaying("partial-transcript");
3079
3094
  }
3080
3095
  lastPartial = controller.partial;
3081
3096
  });
@@ -3085,11 +3100,11 @@ var bindVoiceBargeIn = (controller, player, options = {}) => {
3085
3100
  },
3086
3101
  handleLevel: (level) => {
3087
3102
  if (shouldInterruptForLevel(level, options)) {
3088
- interruptIfPlaying();
3103
+ interruptIfPlaying("input-level");
3089
3104
  }
3090
3105
  },
3091
3106
  sendAudio: (audio) => {
3092
- interruptIfPlaying();
3107
+ interruptIfPlaying("manual-audio");
3093
3108
  controller.sendAudio(audio);
3094
3109
  }
3095
3110
  };
@@ -3119,7 +3134,17 @@ var createVoiceDuplexController = (path, options = {}) => {
3119
3134
  audioPlayer,
3120
3135
  close,
3121
3136
  interruptAssistant: async () => {
3137
+ options.bargeIn?.monitor?.recordRequested({
3138
+ reason: "manual-interrupt",
3139
+ sessionId: controller.sessionId
3140
+ });
3122
3141
  await audioPlayer.interrupt();
3142
+ options.bargeIn?.monitor?.recordStopped({
3143
+ latencyMs: audioPlayer.lastInterruptLatencyMs,
3144
+ playbackStopLatencyMs: audioPlayer.lastPlaybackStopLatencyMs,
3145
+ reason: "manual-interrupt",
3146
+ sessionId: controller.sessionId
3147
+ });
3123
3148
  },
3124
3149
  sendAudio: (audio) => {
3125
3150
  bargeInBinding?.sendAudio(audio);
package/dist/trace.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type VoiceTraceEventType = 'assistant.guardrail' | 'assistant.memory' | 'assistant.run' | 'agent.handoff' | 'agent.model' | 'agent.result' | 'agent.tool' | 'call.handoff' | 'call.lifecycle' | 'session.error' | 'turn.assistant' | 'turn.committed' | 'turn.cost' | 'turn.transcript' | 'workflow.contract';
1
+ export type VoiceTraceEventType = 'assistant.guardrail' | 'assistant.memory' | 'assistant.run' | 'agent.handoff' | 'agent.model' | 'agent.result' | 'agent.tool' | 'call.handoff' | 'call.lifecycle' | 'client.barge_in' | 'session.error' | 'turn.assistant' | 'turn.committed' | 'turn.cost' | 'turn.transcript' | 'workflow.contract';
2
2
  export type VoiceTraceEvent<TPayload extends Record<string, unknown> = Record<string, unknown>> = {
3
3
  at: number;
4
4
  id?: string;
package/dist/types.d.ts CHANGED
@@ -747,6 +747,46 @@ export type VoiceBargeInOptions = {
747
747
  enabled?: boolean;
748
748
  interruptOnPartial?: boolean;
749
749
  interruptThreshold?: number;
750
+ monitor?: VoiceBargeInMonitor;
751
+ };
752
+ export type VoiceBargeInTriggerReason = 'input-level' | 'manual-audio' | 'manual-interrupt' | 'partial-transcript';
753
+ export type VoiceBargeInMonitorEvent = {
754
+ at: number;
755
+ id: string;
756
+ latencyMs?: number;
757
+ playbackStopLatencyMs?: number;
758
+ reason: VoiceBargeInTriggerReason;
759
+ sessionId?: string | null;
760
+ status: 'requested' | 'stopped' | 'skipped';
761
+ thresholdMs?: number;
762
+ };
763
+ export type VoiceBargeInMonitorSnapshot = {
764
+ averageLatencyMs?: number;
765
+ events: VoiceBargeInMonitorEvent[];
766
+ failed: number;
767
+ lastEvent?: VoiceBargeInMonitorEvent;
768
+ passed: number;
769
+ status: 'empty' | 'fail' | 'pass' | 'warn';
770
+ thresholdMs: number;
771
+ total: number;
772
+ };
773
+ export type VoiceBargeInMonitor = {
774
+ getSnapshot: () => VoiceBargeInMonitorSnapshot;
775
+ recordRequested: (input: {
776
+ reason: VoiceBargeInTriggerReason;
777
+ sessionId?: string | null;
778
+ }) => VoiceBargeInMonitorEvent;
779
+ recordSkipped: (input: {
780
+ reason: VoiceBargeInTriggerReason;
781
+ sessionId?: string | null;
782
+ }) => VoiceBargeInMonitorEvent;
783
+ recordStopped: (input: {
784
+ latencyMs?: number;
785
+ playbackStopLatencyMs?: number;
786
+ reason: VoiceBargeInTriggerReason;
787
+ sessionId?: string | null;
788
+ }) => VoiceBargeInMonitorEvent;
789
+ subscribe: (subscriber: () => void) => () => void;
750
790
  };
751
791
  export type VoiceAudioPlayerOptions = {
752
792
  autoStart?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.91",
3
+ "version": "0.0.22-beta.92",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",