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

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.
@@ -3116,7 +3116,13 @@ var createVoiceController = (path, options = {}) => {
3116
3116
  capture = createMicrophoneCapture({
3117
3117
  channelCount: options.capture?.channelCount ?? preset.capture.channelCount,
3118
3118
  onLevel: options.capture?.onLevel,
3119
- onAudio: (audio) => stream.sendAudio(audio),
3119
+ onAudio: (audio) => {
3120
+ if (options.capture?.onAudio) {
3121
+ options.capture.onAudio(audio, stream.sendAudio);
3122
+ return;
3123
+ }
3124
+ stream.sendAudio(audio);
3125
+ },
3120
3126
  sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
3121
3127
  });
3122
3128
  return capture;
@@ -2558,7 +2558,13 @@ var createVoiceController = (path, options = {}) => {
2558
2558
  capture = createMicrophoneCapture({
2559
2559
  channelCount: options.capture?.channelCount ?? preset.capture.channelCount,
2560
2560
  onLevel: options.capture?.onLevel,
2561
- onAudio: (audio) => stream.sendAudio(audio),
2561
+ onAudio: (audio) => {
2562
+ if (options.capture?.onAudio) {
2563
+ options.capture.onAudio(audio, stream.sendAudio);
2564
+ return;
2565
+ }
2566
+ stream.sendAudio(audio);
2567
+ },
2562
2568
  sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
2563
2569
  });
2564
2570
  return capture;
@@ -2948,7 +2948,13 @@ var createVoiceController = (path, options = {}) => {
2948
2948
  capture = createMicrophoneCapture({
2949
2949
  channelCount: options.capture?.channelCount ?? preset.capture.channelCount,
2950
2950
  onLevel: options.capture?.onLevel,
2951
- onAudio: (audio) => stream.sendAudio(audio),
2951
+ onAudio: (audio) => {
2952
+ if (options.capture?.onAudio) {
2953
+ options.capture.onAudio(audio, stream.sendAudio);
2954
+ return;
2955
+ }
2956
+ stream.sendAudio(audio);
2957
+ },
2952
2958
  sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
2953
2959
  });
2954
2960
  return capture;
@@ -3063,11 +3069,26 @@ var DEFAULT_INTERRUPT_THRESHOLD = 0.08;
3063
3069
  var shouldInterruptForLevel = (level, options = {}) => (options.enabled ?? true) && level >= (options.interruptThreshold ?? DEFAULT_INTERRUPT_THRESHOLD);
3064
3070
  var bindVoiceBargeIn = (controller, player, options = {}) => {
3065
3071
  let lastPartial = controller.partial;
3066
- const interruptIfPlaying = () => {
3072
+ const interruptIfPlaying = (reason) => {
3067
3073
  if (!player.isPlaying || options.enabled === false) {
3074
+ options.monitor?.recordSkipped({
3075
+ reason,
3076
+ sessionId: controller.sessionId
3077
+ });
3068
3078
  return;
3069
3079
  }
3070
- player.interrupt();
3080
+ options.monitor?.recordRequested({
3081
+ reason,
3082
+ sessionId: controller.sessionId
3083
+ });
3084
+ player.interrupt().then(() => {
3085
+ options.monitor?.recordStopped({
3086
+ latencyMs: player.lastInterruptLatencyMs,
3087
+ playbackStopLatencyMs: player.lastPlaybackStopLatencyMs,
3088
+ reason,
3089
+ sessionId: controller.sessionId
3090
+ });
3091
+ });
3071
3092
  };
3072
3093
  const unsubscribe = controller.subscribe(() => {
3073
3094
  if (options.interruptOnPartial === false) {
@@ -3075,7 +3096,7 @@ var bindVoiceBargeIn = (controller, player, options = {}) => {
3075
3096
  return;
3076
3097
  }
3077
3098
  if (!lastPartial && controller.partial) {
3078
- interruptIfPlaying();
3099
+ interruptIfPlaying("partial-transcript");
3079
3100
  }
3080
3101
  lastPartial = controller.partial;
3081
3102
  });
@@ -3085,11 +3106,11 @@ var bindVoiceBargeIn = (controller, player, options = {}) => {
3085
3106
  },
3086
3107
  handleLevel: (level) => {
3087
3108
  if (shouldInterruptForLevel(level, options)) {
3088
- interruptIfPlaying();
3109
+ interruptIfPlaying("input-level");
3089
3110
  }
3090
3111
  },
3091
3112
  sendAudio: (audio) => {
3092
- interruptIfPlaying();
3113
+ interruptIfPlaying("manual-audio");
3093
3114
  controller.sendAudio(audio);
3094
3115
  }
3095
3116
  };
@@ -3119,7 +3140,17 @@ var createVoiceDuplexController = (path, options = {}) => {
3119
3140
  audioPlayer,
3120
3141
  close,
3121
3142
  interruptAssistant: async () => {
3143
+ options.bargeIn?.monitor?.recordRequested({
3144
+ reason: "manual-interrupt",
3145
+ sessionId: controller.sessionId
3146
+ });
3122
3147
  await audioPlayer.interrupt();
3148
+ options.bargeIn?.monitor?.recordStopped({
3149
+ latencyMs: audioPlayer.lastInterruptLatencyMs,
3150
+ playbackStopLatencyMs: audioPlayer.lastPlaybackStopLatencyMs,
3151
+ reason: "manual-interrupt",
3152
+ sessionId: controller.sessionId
3153
+ });
3123
3154
  },
3124
3155
  sendAudio: (audio) => {
3125
3156
  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
@@ -734,6 +734,7 @@ export type VoiceConnectionOptions = {
734
734
  };
735
735
  export type VoiceCaptureOptions = {
736
736
  channelCount?: 1 | 2;
737
+ onAudio?: (audio: Uint8Array | ArrayBuffer, sendAudio: (audio: Uint8Array | ArrayBuffer) => void) => void;
737
738
  onLevel?: (level: number) => void;
738
739
  sampleRateHz?: number;
739
740
  };
@@ -747,6 +748,46 @@ export type VoiceBargeInOptions = {
747
748
  enabled?: boolean;
748
749
  interruptOnPartial?: boolean;
749
750
  interruptThreshold?: number;
751
+ monitor?: VoiceBargeInMonitor;
752
+ };
753
+ export type VoiceBargeInTriggerReason = 'input-level' | 'manual-audio' | 'manual-interrupt' | 'partial-transcript';
754
+ export type VoiceBargeInMonitorEvent = {
755
+ at: number;
756
+ id: string;
757
+ latencyMs?: number;
758
+ playbackStopLatencyMs?: number;
759
+ reason: VoiceBargeInTriggerReason;
760
+ sessionId?: string | null;
761
+ status: 'requested' | 'stopped' | 'skipped';
762
+ thresholdMs?: number;
763
+ };
764
+ export type VoiceBargeInMonitorSnapshot = {
765
+ averageLatencyMs?: number;
766
+ events: VoiceBargeInMonitorEvent[];
767
+ failed: number;
768
+ lastEvent?: VoiceBargeInMonitorEvent;
769
+ passed: number;
770
+ status: 'empty' | 'fail' | 'pass' | 'warn';
771
+ thresholdMs: number;
772
+ total: number;
773
+ };
774
+ export type VoiceBargeInMonitor = {
775
+ getSnapshot: () => VoiceBargeInMonitorSnapshot;
776
+ recordRequested: (input: {
777
+ reason: VoiceBargeInTriggerReason;
778
+ sessionId?: string | null;
779
+ }) => VoiceBargeInMonitorEvent;
780
+ recordSkipped: (input: {
781
+ reason: VoiceBargeInTriggerReason;
782
+ sessionId?: string | null;
783
+ }) => VoiceBargeInMonitorEvent;
784
+ recordStopped: (input: {
785
+ latencyMs?: number;
786
+ playbackStopLatencyMs?: number;
787
+ reason: VoiceBargeInTriggerReason;
788
+ sessionId?: string | null;
789
+ }) => VoiceBargeInMonitorEvent;
790
+ subscribe: (subscriber: () => void) => () => void;
750
791
  };
751
792
  export type VoiceAudioPlayerOptions = {
752
793
  autoStart?: boolean;
package/dist/vue/index.js CHANGED
@@ -2891,7 +2891,13 @@ var createVoiceController = (path, options = {}) => {
2891
2891
  capture = createMicrophoneCapture({
2892
2892
  channelCount: options.capture?.channelCount ?? preset.capture.channelCount,
2893
2893
  onLevel: options.capture?.onLevel,
2894
- onAudio: (audio) => stream.sendAudio(audio),
2894
+ onAudio: (audio) => {
2895
+ if (options.capture?.onAudio) {
2896
+ options.capture.onAudio(audio, stream.sendAudio);
2897
+ return;
2898
+ }
2899
+ stream.sendAudio(audio);
2900
+ },
2895
2901
  sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
2896
2902
  });
2897
2903
  return capture;
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.93",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",