@absolutejs/voice 0.0.22-beta.311 → 0.0.22-beta.313

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/dist/index.d.ts CHANGED
@@ -15,8 +15,8 @@ export type { VoiceRealtimeChannelAssertionInput, VoiceRealtimeChannelAssertionR
15
15
  export { assertVoiceRealtimeProviderContractEvidence, buildVoiceRealtimeProviderContractMatrix, createVoiceRealtimeProviderContractMatrixPreset, createVoiceRealtimeProviderContractRoutes, evaluateVoiceRealtimeProviderContractEvidence, renderVoiceRealtimeProviderContractHTML } from './realtimeProviderContracts';
16
16
  export type { VoiceRealtimeProviderContractAssertionInput, VoiceRealtimeProviderContractAssertionReport, VoiceRealtimeProviderContractCapability, VoiceRealtimeProviderContractCheck, VoiceRealtimeProviderContractDefinition, VoiceRealtimeProviderContractMatrixPresetOptions, VoiceRealtimeProviderContractMatrixInput, VoiceRealtimeProviderContractMatrixReport, VoiceRealtimeProviderContractRoutesOptions, VoiceRealtimeProviderContractRow, VoiceRealtimeProviderPresetProvider, VoiceRealtimeProviderContractStatus } from './realtimeProviderContracts';
17
17
  export { buildVoiceDiagnosticsMarkdown, createVoiceDiagnosticsRoutes, resolveVoiceDiagnosticsTraceFilter } from './diagnosticsRoutes';
18
- export { buildVoiceMediaInterruptionReport, buildVoiceMediaPipelineCalibrationReport, buildVoiceMediaResamplingPlan, buildVoiceMediaVadReport, createVoiceMediaFrame, createVoiceMediaFrameTransformPipeline } from './mediaPipeline';
19
- export type { VoiceMediaFrame, VoiceMediaFrameKind, VoiceMediaFrameSource, VoiceMediaFrameTransform, VoiceMediaFrameTransformPipeline, VoiceMediaInterruptionInput, VoiceMediaInterruptionReport, VoiceMediaPipelineCalibrationInput, VoiceMediaPipelineCalibrationIssue, VoiceMediaPipelineCalibrationReport, VoiceMediaPipelineStatus, VoiceMediaResamplingPlan, VoiceMediaTransportAdapter, VoiceMediaVadInput, VoiceMediaVadReport, VoiceMediaVadSegment } from './mediaPipeline';
18
+ export { buildVoiceMediaTransportReport, buildVoiceMediaInterruptionReport, buildVoiceMediaPipelineCalibrationReport, buildVoiceMediaResamplingPlan, buildVoiceMediaProcessorGraphReport, buildVoiceMediaVadReport, createVoiceMediaFrame, createVoiceMediaFrameTransformPipeline, createVoiceMediaProcessorGraph, createVoiceMediaTransport } from './mediaPipeline';
19
+ export type { VoiceMediaFrame, VoiceMediaFrameKind, VoiceMediaFrameSource, VoiceMediaFrameTransform, VoiceMediaFrameTransformPipeline, VoiceMediaInterruptionInput, VoiceMediaInterruptionReport, VoiceMediaPipelineCalibrationInput, VoiceMediaPipelineCalibrationIssue, VoiceMediaPipelineCalibrationReport, VoiceMediaPipelineStatus, VoiceMediaProcessorGraph, VoiceMediaProcessorGraphReport, VoiceMediaProcessorNode, VoiceMediaProcessorNodeEvent, VoiceMediaProcessorNodeKind, VoiceMediaProcessorNodeReport, VoiceMediaResamplingPlan, VoiceMediaTransport, VoiceMediaTransportAdapter, VoiceMediaTransportEvent, VoiceMediaTransportEventKind, VoiceMediaTransportOptions, VoiceMediaTransportReport, VoiceMediaTransportState, VoiceMediaVadInput, VoiceMediaVadReport, VoiceMediaVadSegment } from './mediaPipeline';
20
20
  export { assertVoiceMediaPipelineEvidence, buildVoiceMediaPipelineReport, createVoiceMediaPipelineRoutes, evaluateVoiceMediaPipelineEvidence, renderVoiceMediaPipelineHTML, renderVoiceMediaPipelineMarkdown } from './mediaPipelineRoutes';
21
21
  export type { VoiceMediaPipelineAssertionInput, VoiceMediaPipelineAssertionReport, VoiceMediaPipelineReport, VoiceMediaPipelineReportOptions, VoiceMediaPipelineRoutesOptions } from './mediaPipelineRoutes';
22
22
  export { buildVoiceDemoReadyReport, createVoiceDemoReadyRoutes, renderVoiceDemoReadyHTML } from './demoReadyRoutes';
package/dist/index.js CHANGED
@@ -11620,6 +11620,95 @@ var numericMetadata = (frame, key) => {
11620
11620
  return typeof value === "number" && Number.isFinite(value) ? value : undefined;
11621
11621
  };
11622
11622
  var createVoiceMediaFrame = (frame) => frame;
11623
+ var buildVoiceMediaTransportReport = (input) => {
11624
+ const events = input.events ?? [];
11625
+ const state = input.state ?? events.at(-1)?.state ?? "idle";
11626
+ const backpressureEvents = events.filter((event) => event.kind === "backpressure").length;
11627
+ const failed = state === "failed" || events.some((event) => event.kind === "error");
11628
+ return {
11629
+ backpressureEvents,
11630
+ checkedAt: Date.now(),
11631
+ closed: state === "closed",
11632
+ connected: state === "open",
11633
+ events,
11634
+ failed,
11635
+ inputFrames: events.filter((event) => event.kind === "frame-in").length,
11636
+ name: input.name,
11637
+ outputFrames: events.filter((event) => event.kind === "frame-out").length,
11638
+ state,
11639
+ status: failed ? "fail" : backpressureEvents > 0 ? "warn" : "pass"
11640
+ };
11641
+ };
11642
+ var createVoiceMediaTransport = (options) => {
11643
+ let state = "idle";
11644
+ const events = [];
11645
+ const frameHandlers = new Set;
11646
+ const record = (event) => {
11647
+ events.push({ ...event, at: Date.now(), state });
11648
+ };
11649
+ return {
11650
+ close: async () => {
11651
+ state = "closing";
11652
+ await options.onClose?.();
11653
+ state = "closed";
11654
+ record({ kind: "close" });
11655
+ },
11656
+ connect: async () => {
11657
+ try {
11658
+ await options.onConnect?.();
11659
+ state = "open";
11660
+ record({ kind: "connect" });
11661
+ } catch (error) {
11662
+ state = "failed";
11663
+ record({
11664
+ error: error instanceof Error ? error.message : String(error),
11665
+ kind: "error"
11666
+ });
11667
+ throw error;
11668
+ }
11669
+ },
11670
+ events: () => [...events],
11671
+ inputFormat: options.inputFormat,
11672
+ name: options.name,
11673
+ onFrame: (handler) => {
11674
+ frameHandlers.add(handler);
11675
+ return () => frameHandlers.delete(handler);
11676
+ },
11677
+ outputFormat: options.outputFormat,
11678
+ receive: async (frame) => {
11679
+ record({ frameId: frame.id, kind: "frame-in" });
11680
+ if (options.maxBufferedFrames !== undefined && events.filter((event) => event.kind === "frame-in").length > options.maxBufferedFrames) {
11681
+ record({
11682
+ bufferedFrames: events.filter((event) => event.kind === "frame-in").length,
11683
+ kind: "backpressure"
11684
+ });
11685
+ }
11686
+ for (const handler of frameHandlers) {
11687
+ await handler(frame);
11688
+ }
11689
+ },
11690
+ report: () => buildVoiceMediaTransportReport({
11691
+ events,
11692
+ name: options.name,
11693
+ state
11694
+ }),
11695
+ send: async (frame) => {
11696
+ try {
11697
+ await options.onSend?.(frame);
11698
+ record({ frameId: frame.id, kind: "frame-out" });
11699
+ } catch (error) {
11700
+ state = "failed";
11701
+ record({
11702
+ error: error instanceof Error ? error.message : String(error),
11703
+ frameId: frame.id,
11704
+ kind: "error"
11705
+ });
11706
+ throw error;
11707
+ }
11708
+ },
11709
+ state: () => state
11710
+ };
11711
+ };
11623
11712
  var buildVoiceMediaResamplingPlan = (input) => {
11624
11713
  const required = !formatMatches2(input.inputFormat, input.outputFormat);
11625
11714
  return {
@@ -11663,6 +11752,93 @@ var createVoiceMediaFrameTransformPipeline = (input = {}) => {
11663
11752
  transforms
11664
11753
  };
11665
11754
  };
11755
+ var normalizeProcessorResult = (frame, result) => {
11756
+ if (result === false || result === undefined) {
11757
+ return [];
11758
+ }
11759
+ if (result === true) {
11760
+ return [frame];
11761
+ }
11762
+ if (Array.isArray(result)) {
11763
+ return result;
11764
+ }
11765
+ return [result];
11766
+ };
11767
+ var buildVoiceMediaProcessorGraphReport = (input) => {
11768
+ const events = input.events ?? [];
11769
+ const nodes = input.nodes.map((node) => {
11770
+ const nodeEvents = events.filter((event) => event.node === node.name);
11771
+ const droppedFrames2 = nodeEvents.reduce((total, event) => total + event.dropped, 0);
11772
+ const emittedFrames2 = nodeEvents.reduce((total, event) => total + event.emitted, 0);
11773
+ const inputFrames2 = nodeEvents.reduce((total, event) => total + event.inputs, 0);
11774
+ return {
11775
+ droppedFrames: droppedFrames2,
11776
+ emittedFrames: emittedFrames2,
11777
+ events: nodeEvents,
11778
+ inputFrames: inputFrames2,
11779
+ kind: node.kind ?? "processor",
11780
+ name: node.name,
11781
+ status: inputFrames2 > 0 && emittedFrames2 === 0 && node.kind !== "sink" ? "warn" : "pass"
11782
+ };
11783
+ });
11784
+ const inputFrames = events.filter((event) => event.node === input.nodes[0]?.name).length;
11785
+ const droppedFrames = events.reduce((total, event) => total + event.dropped, 0);
11786
+ const emittedFrames = input.nodes.at(-1) ? events.filter((event) => event.node === input.nodes.at(-1)?.name).reduce((total, event) => total + event.emitted, 0) : 0;
11787
+ const status = nodes.some((node) => node.status === "warn") ? "warn" : "pass";
11788
+ return {
11789
+ checkedAt: Date.now(),
11790
+ droppedFrames,
11791
+ emittedFrames,
11792
+ events,
11793
+ inputFrames,
11794
+ name: input.name,
11795
+ nodes,
11796
+ status
11797
+ };
11798
+ };
11799
+ var createVoiceMediaProcessorGraph = (input = {}) => {
11800
+ const nodes = input.nodes ?? [];
11801
+ const events = [];
11802
+ const process = async (frame) => {
11803
+ let frames = [frame];
11804
+ for (const node of nodes) {
11805
+ const nextFrames = [];
11806
+ for (const current of frames) {
11807
+ const output = normalizeProcessorResult(current, await node.process(current));
11808
+ events.push({
11809
+ at: Date.now(),
11810
+ dropped: output.length === 0 ? 1 : 0,
11811
+ emitted: output.length,
11812
+ frameId: current.id,
11813
+ inputs: 1,
11814
+ node: node.name
11815
+ });
11816
+ nextFrames.push(...output);
11817
+ }
11818
+ frames = nextFrames;
11819
+ if (frames.length === 0) {
11820
+ break;
11821
+ }
11822
+ }
11823
+ return frames;
11824
+ };
11825
+ return {
11826
+ nodes,
11827
+ process,
11828
+ processMany: async (frames) => {
11829
+ const output = [];
11830
+ for (const frame of frames) {
11831
+ output.push(...await process(frame));
11832
+ }
11833
+ return output;
11834
+ },
11835
+ report: () => buildVoiceMediaProcessorGraphReport({
11836
+ events,
11837
+ name: input.name ?? "voice-media-processor-graph",
11838
+ nodes
11839
+ })
11840
+ };
11841
+ };
11666
11842
  var speechProbability = (frame) => {
11667
11843
  if (frame.metadata?.isSpeech === true) {
11668
11844
  return 1;
@@ -11849,7 +12025,9 @@ var buildVoiceMediaPipelineReport = (options = {}) => {
11849
12025
  calibration.status,
11850
12026
  vad.status,
11851
12027
  interruption.status,
11852
- resampling?.status ?? "pass"
12028
+ resampling?.status ?? "pass",
12029
+ options.processorGraph?.status ?? "pass",
12030
+ options.transport?.status ?? "pass"
11853
12031
  ]);
11854
12032
  return {
11855
12033
  calibration,
@@ -11857,9 +12035,11 @@ var buildVoiceMediaPipelineReport = (options = {}) => {
11857
12035
  frames: frames.length,
11858
12036
  interruption,
11859
12037
  ok: status === "pass",
12038
+ processorGraph: options.processorGraph,
11860
12039
  resampling,
11861
12040
  status,
11862
12041
  surface: options.surface ?? "voice-media-pipeline",
12042
+ transport: options.transport,
11863
12043
  vad
11864
12044
  };
11865
12045
  };
@@ -11892,6 +12072,27 @@ var evaluateVoiceMediaPipelineEvidence = (report, input = {}) => {
11892
12072
  if (input.requireResamplingReady && report.calibration.resamplingRequired && !report.resampling) {
11893
12073
  issues.push("Expected resampling plan when calibration requires resampling.");
11894
12074
  }
12075
+ if (input.requireProcessorGraph && !report.processorGraph) {
12076
+ issues.push("Expected media processor graph evidence.");
12077
+ }
12078
+ if (input.minProcessorGraphNodes !== undefined && (report.processorGraph?.nodes.length ?? 0) < input.minProcessorGraphNodes) {
12079
+ issues.push(`Expected at least ${String(input.minProcessorGraphNodes)} media processor node(s), found ${String(report.processorGraph?.nodes.length ?? 0)}.`);
12080
+ }
12081
+ if (input.minProcessorGraphEmittedFrames !== undefined && (report.processorGraph?.emittedFrames ?? 0) < input.minProcessorGraphEmittedFrames) {
12082
+ issues.push(`Expected at least ${String(input.minProcessorGraphEmittedFrames)} processor graph output frame(s), found ${String(report.processorGraph?.emittedFrames ?? 0)}.`);
12083
+ }
12084
+ if (input.requireTransportConnected && !report.transport?.connected) {
12085
+ issues.push("Expected connected media transport evidence.");
12086
+ }
12087
+ if (input.minTransportInputFrames !== undefined && (report.transport?.inputFrames ?? 0) < input.minTransportInputFrames) {
12088
+ issues.push(`Expected at least ${String(input.minTransportInputFrames)} transport input frame(s), found ${String(report.transport?.inputFrames ?? 0)}.`);
12089
+ }
12090
+ if (input.minTransportOutputFrames !== undefined && (report.transport?.outputFrames ?? 0) < input.minTransportOutputFrames) {
12091
+ issues.push(`Expected at least ${String(input.minTransportOutputFrames)} transport output frame(s), found ${String(report.transport?.outputFrames ?? 0)}.`);
12092
+ }
12093
+ if (input.maxTransportBackpressureEvents !== undefined && (report.transport?.backpressureEvents ?? 0) > input.maxTransportBackpressureEvents) {
12094
+ issues.push(`Expected at most ${String(input.maxTransportBackpressureEvents)} transport backpressure event(s), found ${String(report.transport?.backpressureEvents ?? 0)}.`);
12095
+ }
11895
12096
  return {
11896
12097
  issues,
11897
12098
  ok: issues.length === 0,
@@ -11919,6 +12120,13 @@ var renderVoiceMediaPipelineMarkdown = (report) => [
11919
12120
  `- Resampling required: ${report.calibration.resamplingRequired ? "yes" : "no"}`,
11920
12121
  `- VAD segments: ${String(report.vad.segments.length)}`,
11921
12122
  `- Interruption frames: ${String(report.interruption.interruptionFrames)}`,
12123
+ `- Processor graph: ${report.processorGraph ? `${report.processorGraph.name} (${String(report.processorGraph.nodes.length)} nodes)` : "n/a"}`,
12124
+ `- Processor graph emitted frames: ${String(report.processorGraph?.emittedFrames ?? 0)}`,
12125
+ `- Processor graph dropped frames: ${String(report.processorGraph?.droppedFrames ?? 0)}`,
12126
+ `- Transport: ${report.transport ? `${report.transport.name} (${report.transport.state})` : "n/a"}`,
12127
+ `- Transport input frames: ${String(report.transport?.inputFrames ?? 0)}`,
12128
+ `- Transport output frames: ${String(report.transport?.outputFrames ?? 0)}`,
12129
+ `- Transport backpressure events: ${String(report.transport?.backpressureEvents ?? 0)}`,
11922
12130
  "",
11923
12131
  "## Issues",
11924
12132
  "",
@@ -11932,7 +12140,7 @@ var renderVoiceMediaPipelineMarkdown = (report) => [
11932
12140
  var renderVoiceMediaPipelineHTML = (report, title = "Voice Media Pipeline Proof") => {
11933
12141
  const issues = [...report.calibration.issues, ...report.interruption.issues].map((issue) => `<li class="${escapeHtml15(issue.severity)}"><strong>${escapeHtml15(issue.code)}</strong>: ${escapeHtml15(issue.message)}</li>`).join("");
11934
12142
  const segments = report.vad.segments.map((segment) => `<tr><td>${escapeHtml15(segment.segmentId)}</td><td>${escapeHtml15(segment.frameCount)}</td><td>${escapeHtml15(segment.durationMs ?? "n/a")}</td><td>${escapeHtml15(segment.turnId ?? "n/a")}</td></tr>`).join("");
11935
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml15(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero,.card{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr))}.metric{background:#101814;border:1px solid #2e3d36;border-radius:18px;padding:14px}.metric span{color:#a8b5ad;display:block;font-size:.78rem;text-transform:uppercase}.metric strong{display:block;font-size:1.65rem;margin-top:5px}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:7px 11px}.pass{color:#86efac}.warn,.warning{color:#fde68a}.fail,.error{color:#fecaca}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3d36;padding:10px;text-align:left}</style></head><body><main><section class="hero"><p class="eyebrow">Native media pipeline</p><h1>${escapeHtml15(title)}</h1><p class="status ${escapeHtml15(report.status)}">${escapeHtml15(report.status)}</p><p>${escapeHtml15(report.surface)}</p><section class="summary"><div class="metric"><span>Frames</span><strong>${String(report.frames)}</strong></div><div class="metric"><span>Input audio</span><strong>${String(report.calibration.inputAudioFrames)}</strong></div><div class="metric"><span>Assistant audio</span><strong>${String(report.calibration.assistantAudioFrames)}</strong></div><div class="metric"><span>Trace linked</span><strong>${String(report.calibration.traceLinkedFrames)}</strong></div><div class="metric"><span>First audio</span><strong>${escapeHtml15(report.calibration.firstAudioLatencyMs ?? "n/a")}ms</strong></div><div class="metric"><span>VAD segments</span><strong>${String(report.vad.segments.length)}</strong></div><div class="metric"><span>Interruptions</span><strong>${String(report.interruption.interruptionFrames)}</strong></div><div class="metric"><span>Resampling</span><strong>${report.calibration.resamplingRequired ? "required" : "not required"}</strong></div></section></section><section class="card"><h2>Issues</h2><ul>${issues || '<li class="pass">No media pipeline issues.</li>'}</ul></section><section class="card"><h2>VAD Segments</h2><table><thead><tr><th>Segment</th><th>Frames</th><th>Duration ms</th><th>Turn</th></tr></thead><tbody>${segments || '<tr><td colspan="4">No VAD segments.</td></tr>'}</tbody></table></section></main></body></html>`;
12143
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml15(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero,.card{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr))}.metric{background:#101814;border:1px solid #2e3d36;border-radius:18px;padding:14px}.metric span{color:#a8b5ad;display:block;font-size:.78rem;text-transform:uppercase}.metric strong{display:block;font-size:1.65rem;margin-top:5px}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:7px 11px}.pass{color:#86efac}.warn,.warning{color:#fde68a}.fail,.error{color:#fecaca}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3d36;padding:10px;text-align:left}</style></head><body><main><section class="hero"><p class="eyebrow">Native media pipeline</p><h1>${escapeHtml15(title)}</h1><p class="status ${escapeHtml15(report.status)}">${escapeHtml15(report.status)}</p><p>${escapeHtml15(report.surface)}</p><section class="summary"><div class="metric"><span>Frames</span><strong>${String(report.frames)}</strong></div><div class="metric"><span>Input audio</span><strong>${String(report.calibration.inputAudioFrames)}</strong></div><div class="metric"><span>Assistant audio</span><strong>${String(report.calibration.assistantAudioFrames)}</strong></div><div class="metric"><span>Trace linked</span><strong>${String(report.calibration.traceLinkedFrames)}</strong></div><div class="metric"><span>First audio</span><strong>${escapeHtml15(report.calibration.firstAudioLatencyMs ?? "n/a")}ms</strong></div><div class="metric"><span>VAD segments</span><strong>${String(report.vad.segments.length)}</strong></div><div class="metric"><span>Interruptions</span><strong>${String(report.interruption.interruptionFrames)}</strong></div><div class="metric"><span>Processor graph</span><strong>${String(report.processorGraph?.nodes.length ?? 0)} nodes</strong></div><div class="metric"><span>Graph out/drop</span><strong>${String(report.processorGraph?.emittedFrames ?? 0)}/${String(report.processorGraph?.droppedFrames ?? 0)}</strong></div><div class="metric"><span>Resampling</span><strong>${report.calibration.resamplingRequired ? "required" : "not required"}</strong></div><div class="metric"><span>Transport</span><strong>${escapeHtml15(report.transport?.state ?? "n/a")}</strong></div><div class="metric"><span>Transport in/out</span><strong>${String(report.transport?.inputFrames ?? 0)}/${String(report.transport?.outputFrames ?? 0)}</strong></div><div class="metric"><span>Backpressure</span><strong>${String(report.transport?.backpressureEvents ?? 0)}</strong></div></section></section><section class="card"><h2>Issues</h2><ul>${issues || '<li class="pass">No media pipeline issues.</li>'}</ul></section><section class="card"><h2>VAD Segments</h2><table><thead><tr><th>Segment</th><th>Frames</th><th>Duration ms</th><th>Turn</th></tr></thead><tbody>${segments || '<tr><td colspan="4">No VAD segments.</td></tr>'}</tbody></table></section></main></body></html>`;
11936
12144
  };
11937
12145
  var createVoiceMediaPipelineRoutes = (options = {}) => {
11938
12146
  const path = options.path ?? "/api/voice/media-pipeline";
@@ -34763,6 +34971,8 @@ export {
34763
34971
  createVoiceMemoryAuditSinkDeliveryStore,
34764
34972
  createVoiceMemoryAuditEventStore,
34765
34973
  createVoiceMemoryAssistantMemoryStore,
34974
+ createVoiceMediaTransport,
34975
+ createVoiceMediaProcessorGraph,
34766
34976
  createVoiceMediaPipelineRoutes,
34767
34977
  createVoiceMediaFrameTransformPipeline,
34768
34978
  createVoiceMediaFrame,
@@ -34915,7 +35125,9 @@ export {
34915
35125
  buildVoiceObservabilityArtifactIndex,
34916
35126
  buildVoiceMonitorRunReport,
34917
35127
  buildVoiceMediaVadReport,
35128
+ buildVoiceMediaTransportReport,
34918
35129
  buildVoiceMediaResamplingPlan,
35130
+ buildVoiceMediaProcessorGraphReport,
34919
35131
  buildVoiceMediaPipelineReport,
34920
35132
  buildVoiceMediaPipelineCalibrationReport,
34921
35133
  buildVoiceMediaInterruptionReport,
@@ -34,6 +34,47 @@ export type VoiceMediaFrameTransformPipeline = {
34
34
  pushMany: (frames: readonly VoiceMediaFrame[]) => Promise<readonly VoiceMediaFrame[]>;
35
35
  transforms: readonly VoiceMediaFrameTransform[];
36
36
  };
37
+ export type VoiceMediaProcessorNodeKind = 'branch' | 'filter' | 'processor' | 'sink';
38
+ export type VoiceMediaProcessorNodeEvent = {
39
+ at: number;
40
+ dropped: number;
41
+ emitted: number;
42
+ frameId: string;
43
+ inputs: number;
44
+ node: string;
45
+ };
46
+ export type VoiceMediaProcessorNodeReport = {
47
+ droppedFrames: number;
48
+ emittedFrames: number;
49
+ events: readonly VoiceMediaProcessorNodeEvent[];
50
+ inputFrames: number;
51
+ kind: VoiceMediaProcessorNodeKind;
52
+ name: string;
53
+ status: VoiceMediaPipelineStatus;
54
+ };
55
+ export type VoiceMediaProcessorGraphReport = {
56
+ checkedAt: number;
57
+ droppedFrames: number;
58
+ emittedFrames: number;
59
+ events: readonly VoiceMediaProcessorNodeEvent[];
60
+ inputFrames: number;
61
+ name: string;
62
+ nodes: readonly VoiceMediaProcessorNodeReport[];
63
+ status: VoiceMediaPipelineStatus;
64
+ };
65
+ export type VoiceMediaProcessorNode = {
66
+ inputFormat?: AudioFormat;
67
+ kind?: VoiceMediaProcessorNodeKind;
68
+ name: string;
69
+ outputFormat?: AudioFormat;
70
+ process: (frame: VoiceMediaFrame) => boolean | VoiceMediaFrame | readonly VoiceMediaFrame[] | undefined | Promise<boolean | VoiceMediaFrame | readonly VoiceMediaFrame[] | undefined>;
71
+ };
72
+ export type VoiceMediaProcessorGraph = {
73
+ nodes: readonly VoiceMediaProcessorNode[];
74
+ process: (frame: VoiceMediaFrame) => Promise<readonly VoiceMediaFrame[]>;
75
+ processMany: (frames: readonly VoiceMediaFrame[]) => Promise<readonly VoiceMediaFrame[]>;
76
+ report: () => VoiceMediaProcessorGraphReport;
77
+ };
37
78
  export type VoiceMediaTransportAdapter = {
38
79
  close?: () => Promise<void> | void;
39
80
  connect?: () => Promise<void> | void;
@@ -43,6 +84,44 @@ export type VoiceMediaTransportAdapter = {
43
84
  outputFormat?: AudioFormat;
44
85
  send: (frame: VoiceMediaFrame) => Promise<void> | void;
45
86
  };
87
+ export type VoiceMediaTransportState = 'closed' | 'closing' | 'failed' | 'idle' | 'open';
88
+ export type VoiceMediaTransportEventKind = 'backpressure' | 'close' | 'connect' | 'error' | 'frame-in' | 'frame-out';
89
+ export type VoiceMediaTransportEvent = {
90
+ at: number;
91
+ bufferedFrames?: number;
92
+ error?: string;
93
+ frameId?: string;
94
+ kind: VoiceMediaTransportEventKind;
95
+ state: VoiceMediaTransportState;
96
+ };
97
+ export type VoiceMediaTransportReport = {
98
+ backpressureEvents: number;
99
+ checkedAt: number;
100
+ closed: boolean;
101
+ connected: boolean;
102
+ events: readonly VoiceMediaTransportEvent[];
103
+ failed: boolean;
104
+ inputFrames: number;
105
+ name: string;
106
+ outputFrames: number;
107
+ state: VoiceMediaTransportState;
108
+ status: VoiceMediaPipelineStatus;
109
+ };
110
+ export type VoiceMediaTransport = VoiceMediaTransportAdapter & {
111
+ events: () => readonly VoiceMediaTransportEvent[];
112
+ receive: (frame: VoiceMediaFrame) => Promise<void>;
113
+ report: () => VoiceMediaTransportReport;
114
+ state: () => VoiceMediaTransportState;
115
+ };
116
+ export type VoiceMediaTransportOptions = {
117
+ inputFormat?: AudioFormat;
118
+ maxBufferedFrames?: number;
119
+ name: string;
120
+ onClose?: () => Promise<void> | void;
121
+ onConnect?: () => Promise<void> | void;
122
+ onSend?: (frame: VoiceMediaFrame) => Promise<void> | void;
123
+ outputFormat?: AudioFormat;
124
+ };
46
125
  export type VoiceMediaPipelineCalibrationInput = {
47
126
  expectedInputFormat?: AudioFormat;
48
127
  expectedOutputFormat?: AudioFormat;
@@ -113,6 +192,12 @@ export type VoiceMediaInterruptionReport = {
113
192
  status: VoiceMediaPipelineStatus;
114
193
  };
115
194
  export declare const createVoiceMediaFrame: (frame: VoiceMediaFrame) => VoiceMediaFrame;
195
+ export declare const buildVoiceMediaTransportReport: (input: {
196
+ events?: readonly VoiceMediaTransportEvent[];
197
+ name: string;
198
+ state?: VoiceMediaTransportState;
199
+ }) => VoiceMediaTransportReport;
200
+ export declare const createVoiceMediaTransport: (options: VoiceMediaTransportOptions) => VoiceMediaTransport;
116
201
  export declare const buildVoiceMediaResamplingPlan: (input: {
117
202
  inputFormat: AudioFormat;
118
203
  outputFormat: AudioFormat;
@@ -120,6 +205,15 @@ export declare const buildVoiceMediaResamplingPlan: (input: {
120
205
  export declare const createVoiceMediaFrameTransformPipeline: (input?: {
121
206
  transforms?: readonly VoiceMediaFrameTransform[];
122
207
  }) => VoiceMediaFrameTransformPipeline;
208
+ export declare const buildVoiceMediaProcessorGraphReport: (input: {
209
+ events?: readonly VoiceMediaProcessorNodeEvent[];
210
+ name: string;
211
+ nodes: readonly VoiceMediaProcessorNode[];
212
+ }) => VoiceMediaProcessorGraphReport;
213
+ export declare const createVoiceMediaProcessorGraph: (input?: {
214
+ name?: string;
215
+ nodes?: readonly VoiceMediaProcessorNode[];
216
+ }) => VoiceMediaProcessorGraph;
123
217
  export declare const buildVoiceMediaVadReport: (input?: VoiceMediaVadInput) => VoiceMediaVadReport;
124
218
  export declare const buildVoiceMediaInterruptionReport: (input?: VoiceMediaInterruptionInput) => VoiceMediaInterruptionReport;
125
219
  export declare const buildVoiceMediaPipelineCalibrationReport: (input?: VoiceMediaPipelineCalibrationInput) => VoiceMediaPipelineCalibrationReport;
@@ -1,12 +1,14 @@
1
1
  import { Elysia } from 'elysia';
2
- import { type VoiceMediaFrame, type VoiceMediaInterruptionReport, type VoiceMediaPipelineCalibrationInput, type VoiceMediaPipelineCalibrationReport, type VoiceMediaPipelineStatus, type VoiceMediaResamplingPlan, type VoiceMediaVadReport } from './mediaPipeline';
2
+ import { type VoiceMediaFrame, type VoiceMediaInterruptionReport, type VoiceMediaPipelineCalibrationInput, type VoiceMediaPipelineCalibrationReport, type VoiceMediaPipelineStatus, type VoiceMediaProcessorGraphReport, type VoiceMediaResamplingPlan, type VoiceMediaTransportReport, type VoiceMediaVadReport } from './mediaPipeline';
3
3
  export type VoiceMediaPipelineReportOptions = VoiceMediaPipelineCalibrationInput & {
4
4
  frames?: readonly VoiceMediaFrame[];
5
5
  maxInterruptionLatencyMs?: number;
6
6
  maxSilenceFrames?: number;
7
7
  minSpeechFrames?: number;
8
+ processorGraph?: VoiceMediaProcessorGraphReport;
8
9
  speechEndThreshold?: number;
9
10
  speechStartThreshold?: number;
11
+ transport?: VoiceMediaTransportReport;
10
12
  };
11
13
  export type VoiceMediaPipelineReport = {
12
14
  calibration: VoiceMediaPipelineCalibrationReport;
@@ -15,8 +17,10 @@ export type VoiceMediaPipelineReport = {
15
17
  interruption: VoiceMediaInterruptionReport;
16
18
  ok: boolean;
17
19
  resampling?: VoiceMediaResamplingPlan;
20
+ processorGraph?: VoiceMediaProcessorGraphReport;
18
21
  status: VoiceMediaPipelineStatus;
19
22
  surface: string;
23
+ transport?: VoiceMediaTransportReport;
20
24
  vad: VoiceMediaVadReport;
21
25
  };
22
26
  export type VoiceMediaPipelineAssertionInput = {
@@ -24,11 +28,18 @@ export type VoiceMediaPipelineAssertionInput = {
24
28
  maxInterruptionLatencyMs?: number;
25
29
  minAssistantAudioFrames?: number;
26
30
  minInputAudioFrames?: number;
31
+ minProcessorGraphEmittedFrames?: number;
32
+ minProcessorGraphNodes?: number;
33
+ minTransportInputFrames?: number;
34
+ minTransportOutputFrames?: number;
27
35
  minTraceLinkedFrames?: number;
28
36
  minVadSegments?: number;
37
+ maxTransportBackpressureEvents?: number;
29
38
  requireInterruptionFrame?: boolean;
30
39
  requirePass?: boolean;
40
+ requireProcessorGraph?: boolean;
31
41
  requireResamplingReady?: boolean;
42
+ requireTransportConnected?: boolean;
32
43
  };
33
44
  export type VoiceMediaPipelineAssertionReport = {
34
45
  issues: string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.311",
3
+ "version": "0.0.22-beta.313",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",