@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.
- package/dist/appKit.d.ts +3 -1
- package/dist/bargeInRoutes.d.ts +56 -0
- package/dist/client/bargeInMonitor.d.ts +7 -0
- package/dist/client/duplex.d.ts +1 -1
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +101 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.js +307 -213
- package/dist/testing/index.js +30 -5
- package/dist/trace.d.ts +1 -1
- package/dist/types.d.ts +40 -0
- package/package.json +1 -1
package/dist/appKit.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Elysia } from 'elysia';
|
|
2
2
|
import { type VoiceAssistantHealthRoutesOptions } from './assistantHealth';
|
|
3
|
+
import { type VoiceBargeInRoutesOptions } from './bargeInRoutes';
|
|
3
4
|
import { type VoiceDiagnosticsRoutesOptions } from './diagnosticsRoutes';
|
|
4
5
|
import { type VoiceEvalRoutesOptions, type VoiceEvalLink } from './evalRoutes';
|
|
5
6
|
import { type VoiceHandoffHealthRoutesOptions } from './handoffHealth';
|
|
@@ -12,7 +13,7 @@ import { type VoiceResilienceRoutesOptions } from './resilienceRoutes';
|
|
|
12
13
|
import { type VoiceSessionListRoutesOptions, type VoiceSessionReplayRoutesOptions } from './sessionReplay';
|
|
13
14
|
import { type VoiceTraceEventStore } from './trace';
|
|
14
15
|
import { type VoiceTraceTimelineRoutesOptions } from './traceTimeline';
|
|
15
|
-
export type VoiceAppKitSurface = 'assistantHealth' | 'diagnostics' | 'evals' | 'handoffs' | 'opsConsole' | 'providerCapabilities' | 'providerHealth' | 'productionReadiness' | 'quality' | 'resilience' | 'sessionReplay' | 'sessions' | 'traceTimeline';
|
|
16
|
+
export type VoiceAppKitSurface = 'assistantHealth' | 'bargeIn' | 'diagnostics' | 'evals' | 'handoffs' | 'opsConsole' | 'providerCapabilities' | 'providerHealth' | 'productionReadiness' | 'quality' | 'resilience' | 'sessionReplay' | 'sessions' | 'traceTimeline';
|
|
16
17
|
export type VoiceAppKitLink = VoiceEvalLink & {
|
|
17
18
|
description?: string;
|
|
18
19
|
statusHref?: string;
|
|
@@ -20,6 +21,7 @@ export type VoiceAppKitLink = VoiceEvalLink & {
|
|
|
20
21
|
export type VoiceAppKitRoutesOptions<TProvider extends string = string> = {
|
|
21
22
|
appStatus?: false | VoiceAppKitStatusOptions;
|
|
22
23
|
assistantHealth?: false | Partial<VoiceAssistantHealthRoutesOptions<TProvider>>;
|
|
24
|
+
bargeIn?: false | Partial<VoiceBargeInRoutesOptions>;
|
|
23
25
|
diagnostics?: false | Partial<Omit<VoiceDiagnosticsRoutesOptions, 'store'>>;
|
|
24
26
|
evals?: false | Partial<VoiceEvalRoutesOptions>;
|
|
25
27
|
handoffs?: false | Partial<VoiceHandoffHealthRoutesOptions>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import type { StoredVoiceTraceEvent, VoiceTraceEventStore } from './trace';
|
|
3
|
+
import type { VoiceBargeInMonitorSnapshot } from './types';
|
|
4
|
+
export type VoiceBargeInRoutesOptions = {
|
|
5
|
+
headers?: HeadersInit;
|
|
6
|
+
htmlPath?: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
path?: string;
|
|
9
|
+
store: VoiceTraceEventStore;
|
|
10
|
+
thresholdMs?: number;
|
|
11
|
+
title?: string;
|
|
12
|
+
};
|
|
13
|
+
export type VoiceBargeInReport = VoiceBargeInMonitorSnapshot & {
|
|
14
|
+
checkedAt: number;
|
|
15
|
+
sessions: Array<{
|
|
16
|
+
averageLatencyMs?: number;
|
|
17
|
+
failed: number;
|
|
18
|
+
passed: number;
|
|
19
|
+
sessionId: string;
|
|
20
|
+
total: number;
|
|
21
|
+
}>;
|
|
22
|
+
};
|
|
23
|
+
export declare const summarizeVoiceBargeIn: (events: StoredVoiceTraceEvent[], options?: {
|
|
24
|
+
thresholdMs?: number;
|
|
25
|
+
}) => VoiceBargeInReport;
|
|
26
|
+
export declare const renderVoiceBargeInHTML: (report: VoiceBargeInReport, options?: {
|
|
27
|
+
title?: string;
|
|
28
|
+
}) => string;
|
|
29
|
+
export declare const createVoiceBargeInRoutes: (options: VoiceBargeInRoutesOptions) => Elysia<"", {
|
|
30
|
+
decorator: {};
|
|
31
|
+
store: {};
|
|
32
|
+
derive: {};
|
|
33
|
+
resolve: {};
|
|
34
|
+
}, {
|
|
35
|
+
typebox: {};
|
|
36
|
+
error: {};
|
|
37
|
+
}, {
|
|
38
|
+
schema: {};
|
|
39
|
+
standaloneSchema: {};
|
|
40
|
+
macro: {};
|
|
41
|
+
macroFn: {};
|
|
42
|
+
parser: {};
|
|
43
|
+
response: {};
|
|
44
|
+
}, {}, {
|
|
45
|
+
derive: {};
|
|
46
|
+
resolve: {};
|
|
47
|
+
schema: {};
|
|
48
|
+
standaloneSchema: {};
|
|
49
|
+
response: {};
|
|
50
|
+
}, {
|
|
51
|
+
derive: {};
|
|
52
|
+
resolve: {};
|
|
53
|
+
schema: {};
|
|
54
|
+
standaloneSchema: {};
|
|
55
|
+
response: {};
|
|
56
|
+
}>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { VoiceBargeInMonitor } from '../types';
|
|
2
|
+
export type VoiceBargeInMonitorOptions = {
|
|
3
|
+
fetch?: typeof fetch;
|
|
4
|
+
path?: string;
|
|
5
|
+
thresholdMs?: number;
|
|
6
|
+
};
|
|
7
|
+
export declare const createVoiceBargeInMonitor: (options?: VoiceBargeInMonitorOptions) => VoiceBargeInMonitor;
|
package/dist/client/duplex.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { VoiceAudioPlayer, VoiceBargeInBinding, VoiceBargeInOptions, VoiceController, VoiceDuplexController, VoiceDuplexControllerOptions } from '../types';
|
|
2
|
-
export declare const bindVoiceBargeIn: <TResult = unknown>(controller: Pick<VoiceController<TResult>, "partial" | "sendAudio" | "subscribe">, player: Pick<VoiceAudioPlayer, "interrupt" | "isPlaying">, options?: VoiceBargeInOptions) => VoiceBargeInBinding;
|
|
2
|
+
export declare const bindVoiceBargeIn: <TResult = unknown>(controller: Pick<VoiceController<TResult>, "partial" | "sendAudio" | "sessionId" | "subscribe">, player: Pick<VoiceAudioPlayer, "interrupt" | "isPlaying" | "lastInterruptLatencyMs" | "lastPlaybackStopLatencyMs">, options?: VoiceBargeInOptions) => VoiceBargeInBinding;
|
|
3
3
|
export declare const createVoiceDuplexController: <TResult = unknown>(path: string, options?: VoiceDuplexControllerOptions) => VoiceDuplexController<TResult>;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { createVoiceController } from './controller';
|
|
|
5
5
|
export { bindVoiceBargeIn, createVoiceDuplexController } from './duplex';
|
|
6
6
|
export { bindVoiceHTMX } from './htmx';
|
|
7
7
|
export { createMicrophoneCapture } from './microphone';
|
|
8
|
+
export { createVoiceBargeInMonitor } from './bargeInMonitor';
|
|
8
9
|
export { createVoiceAppKitStatusStore, fetchVoiceAppKitStatus } from './appKitStatus';
|
|
9
10
|
export { createVoiceOpsStatusViewModel, defineVoiceOpsStatusElement, getVoiceOpsStatusCSS, getVoiceOpsStatusLabel, mountVoiceOpsStatus, renderVoiceOpsStatusHTML } from './opsStatusWidget';
|
|
10
11
|
export { createVoiceRoutingStatusStore, fetchVoiceRoutingStatus } from './routingStatus';
|
|
@@ -21,6 +22,7 @@ export { createVoiceTurnQualityViewModel, defineVoiceTurnQualityElement, getVoic
|
|
|
21
22
|
export { createVoiceTraceTimelineViewModel, defineVoiceTraceTimelineElement, getVoiceTraceTimelineCSS, mountVoiceTraceTimeline, renderVoiceTraceTimelineWidgetHTML } from './traceTimelineWidget';
|
|
22
23
|
export { createVoiceWorkflowStatusStore, fetchVoiceWorkflowStatus } from './workflowStatus';
|
|
23
24
|
export type { VoiceAppKitStatusClientOptions, VoiceAppKitStatusSnapshot } from './appKitStatus';
|
|
25
|
+
export type { VoiceBargeInMonitorOptions } from './bargeInMonitor';
|
|
24
26
|
export type { VoiceOpsStatusSurfaceView, VoiceOpsStatusViewModel, VoiceOpsStatusWidgetOptions } from './opsStatusWidget';
|
|
25
27
|
export type { VoiceRoutingStatusClientOptions, VoiceRoutingStatusSnapshot } from './routingStatus';
|
|
26
28
|
export type { VoiceRoutingStatusViewModel, VoiceRoutingStatusWidgetOptions } from './routingStatusWidget';
|
package/dist/client/index.js
CHANGED
|
@@ -1560,11 +1560,26 @@ var DEFAULT_INTERRUPT_THRESHOLD = 0.08;
|
|
|
1560
1560
|
var shouldInterruptForLevel = (level, options = {}) => (options.enabled ?? true) && level >= (options.interruptThreshold ?? DEFAULT_INTERRUPT_THRESHOLD);
|
|
1561
1561
|
var bindVoiceBargeIn = (controller, player, options = {}) => {
|
|
1562
1562
|
let lastPartial = controller.partial;
|
|
1563
|
-
const interruptIfPlaying = () => {
|
|
1563
|
+
const interruptIfPlaying = (reason) => {
|
|
1564
1564
|
if (!player.isPlaying || options.enabled === false) {
|
|
1565
|
+
options.monitor?.recordSkipped({
|
|
1566
|
+
reason,
|
|
1567
|
+
sessionId: controller.sessionId
|
|
1568
|
+
});
|
|
1565
1569
|
return;
|
|
1566
1570
|
}
|
|
1567
|
-
|
|
1571
|
+
options.monitor?.recordRequested({
|
|
1572
|
+
reason,
|
|
1573
|
+
sessionId: controller.sessionId
|
|
1574
|
+
});
|
|
1575
|
+
player.interrupt().then(() => {
|
|
1576
|
+
options.monitor?.recordStopped({
|
|
1577
|
+
latencyMs: player.lastInterruptLatencyMs,
|
|
1578
|
+
playbackStopLatencyMs: player.lastPlaybackStopLatencyMs,
|
|
1579
|
+
reason,
|
|
1580
|
+
sessionId: controller.sessionId
|
|
1581
|
+
});
|
|
1582
|
+
});
|
|
1568
1583
|
};
|
|
1569
1584
|
const unsubscribe = controller.subscribe(() => {
|
|
1570
1585
|
if (options.interruptOnPartial === false) {
|
|
@@ -1572,7 +1587,7 @@ var bindVoiceBargeIn = (controller, player, options = {}) => {
|
|
|
1572
1587
|
return;
|
|
1573
1588
|
}
|
|
1574
1589
|
if (!lastPartial && controller.partial) {
|
|
1575
|
-
interruptIfPlaying();
|
|
1590
|
+
interruptIfPlaying("partial-transcript");
|
|
1576
1591
|
}
|
|
1577
1592
|
lastPartial = controller.partial;
|
|
1578
1593
|
});
|
|
@@ -1582,11 +1597,11 @@ var bindVoiceBargeIn = (controller, player, options = {}) => {
|
|
|
1582
1597
|
},
|
|
1583
1598
|
handleLevel: (level) => {
|
|
1584
1599
|
if (shouldInterruptForLevel(level, options)) {
|
|
1585
|
-
interruptIfPlaying();
|
|
1600
|
+
interruptIfPlaying("input-level");
|
|
1586
1601
|
}
|
|
1587
1602
|
},
|
|
1588
1603
|
sendAudio: (audio) => {
|
|
1589
|
-
interruptIfPlaying();
|
|
1604
|
+
interruptIfPlaying("manual-audio");
|
|
1590
1605
|
controller.sendAudio(audio);
|
|
1591
1606
|
}
|
|
1592
1607
|
};
|
|
@@ -1616,13 +1631,93 @@ var createVoiceDuplexController = (path, options = {}) => {
|
|
|
1616
1631
|
audioPlayer,
|
|
1617
1632
|
close,
|
|
1618
1633
|
interruptAssistant: async () => {
|
|
1634
|
+
options.bargeIn?.monitor?.recordRequested({
|
|
1635
|
+
reason: "manual-interrupt",
|
|
1636
|
+
sessionId: controller.sessionId
|
|
1637
|
+
});
|
|
1619
1638
|
await audioPlayer.interrupt();
|
|
1639
|
+
options.bargeIn?.monitor?.recordStopped({
|
|
1640
|
+
latencyMs: audioPlayer.lastInterruptLatencyMs,
|
|
1641
|
+
playbackStopLatencyMs: audioPlayer.lastPlaybackStopLatencyMs,
|
|
1642
|
+
reason: "manual-interrupt",
|
|
1643
|
+
sessionId: controller.sessionId
|
|
1644
|
+
});
|
|
1620
1645
|
},
|
|
1621
1646
|
sendAudio: (audio) => {
|
|
1622
1647
|
bargeInBinding?.sendAudio(audio);
|
|
1623
1648
|
}
|
|
1624
1649
|
};
|
|
1625
1650
|
};
|
|
1651
|
+
// src/client/bargeInMonitor.ts
|
|
1652
|
+
var DEFAULT_THRESHOLD_MS = 250;
|
|
1653
|
+
var createEventId = () => `barge-in:${Date.now()}:${crypto.randomUUID?.() ?? Math.random().toString(36).slice(2)}`;
|
|
1654
|
+
var summarize = (events, thresholdMs) => {
|
|
1655
|
+
const stopped = events.filter((event) => event.status === "stopped");
|
|
1656
|
+
const latencies = stopped.map((event) => event.latencyMs).filter((value) => typeof value === "number");
|
|
1657
|
+
const failed = stopped.filter((event) => typeof event.latencyMs === "number" && event.latencyMs > thresholdMs).length;
|
|
1658
|
+
const passed = stopped.length - failed;
|
|
1659
|
+
return {
|
|
1660
|
+
averageLatencyMs: latencies.length > 0 ? Math.round(latencies.reduce((total, value) => total + value, 0) / latencies.length) : undefined,
|
|
1661
|
+
events: [...events],
|
|
1662
|
+
failed,
|
|
1663
|
+
lastEvent: events.at(-1),
|
|
1664
|
+
passed,
|
|
1665
|
+
status: events.length === 0 ? "empty" : failed > 0 ? "fail" : stopped.length === 0 ? "warn" : "pass",
|
|
1666
|
+
thresholdMs,
|
|
1667
|
+
total: stopped.length
|
|
1668
|
+
};
|
|
1669
|
+
};
|
|
1670
|
+
var createVoiceBargeInMonitor = (options = {}) => {
|
|
1671
|
+
const listeners = new Set;
|
|
1672
|
+
const thresholdMs = options.thresholdMs ?? DEFAULT_THRESHOLD_MS;
|
|
1673
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
1674
|
+
const events = [];
|
|
1675
|
+
const emit = () => {
|
|
1676
|
+
for (const listener of listeners) {
|
|
1677
|
+
listener();
|
|
1678
|
+
}
|
|
1679
|
+
};
|
|
1680
|
+
const postEvent = (event) => {
|
|
1681
|
+
if (!options.path || typeof fetchImpl !== "function") {
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
fetchImpl(options.path, {
|
|
1685
|
+
body: JSON.stringify(event),
|
|
1686
|
+
headers: {
|
|
1687
|
+
"Content-Type": "application/json"
|
|
1688
|
+
},
|
|
1689
|
+
method: "POST"
|
|
1690
|
+
}).catch(() => {});
|
|
1691
|
+
};
|
|
1692
|
+
const record = (status, input) => {
|
|
1693
|
+
const event = {
|
|
1694
|
+
at: Date.now(),
|
|
1695
|
+
id: createEventId(),
|
|
1696
|
+
latencyMs: input.latencyMs,
|
|
1697
|
+
playbackStopLatencyMs: input.playbackStopLatencyMs,
|
|
1698
|
+
reason: input.reason,
|
|
1699
|
+
sessionId: input.sessionId,
|
|
1700
|
+
status,
|
|
1701
|
+
thresholdMs
|
|
1702
|
+
};
|
|
1703
|
+
events.push(event);
|
|
1704
|
+
postEvent(event);
|
|
1705
|
+
emit();
|
|
1706
|
+
return event;
|
|
1707
|
+
};
|
|
1708
|
+
return {
|
|
1709
|
+
getSnapshot: () => summarize(events, thresholdMs),
|
|
1710
|
+
recordRequested: (input) => record("requested", input),
|
|
1711
|
+
recordSkipped: (input) => record("skipped", input),
|
|
1712
|
+
recordStopped: (input) => record("stopped", input),
|
|
1713
|
+
subscribe: (subscriber) => {
|
|
1714
|
+
listeners.add(subscriber);
|
|
1715
|
+
return () => {
|
|
1716
|
+
listeners.delete(subscriber);
|
|
1717
|
+
};
|
|
1718
|
+
}
|
|
1719
|
+
};
|
|
1720
|
+
};
|
|
1626
1721
|
// src/client/appKitStatus.ts
|
|
1627
1722
|
var fetchVoiceAppKitStatus = async (path = "/app-kit/status", options = {}) => {
|
|
1628
1723
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
@@ -3046,6 +3141,7 @@ export {
|
|
|
3046
3141
|
createVoiceDuplexController,
|
|
3047
3142
|
createVoiceController,
|
|
3048
3143
|
createVoiceConnection,
|
|
3144
|
+
createVoiceBargeInMonitor,
|
|
3049
3145
|
createVoiceAudioPlayer,
|
|
3050
3146
|
createVoiceAppKitStatusStore,
|
|
3051
3147
|
createMicrophoneCapture,
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { voice } from './plugin';
|
|
|
2
2
|
export { createVoiceAppKit, createVoiceAppKitRoutes, summarizeVoiceAppKitStatus } from './appKit';
|
|
3
3
|
export { createVoiceAssistant, createVoiceExperiment, summarizeVoiceAssistantRuns } from './assistant';
|
|
4
4
|
export { createVoiceAssistantHealthHTMLHandler, createVoiceAssistantHealthJSONHandler, createVoiceAssistantHealthRoutes, renderVoiceAssistantHealthHTML, summarizeVoiceAssistantHealth } from './assistantHealth';
|
|
5
|
+
export { createVoiceBargeInRoutes, renderVoiceBargeInHTML, summarizeVoiceBargeIn } from './bargeInRoutes';
|
|
5
6
|
export { buildVoiceDiagnosticsMarkdown, createVoiceDiagnosticsRoutes, resolveVoiceDiagnosticsTraceFilter } from './diagnosticsRoutes';
|
|
6
7
|
export { compareVoiceEvalBaseline, createVoiceFileEvalBaselineStore, createVoiceFileScenarioFixtureStore, createVoiceEvalRoutes, renderVoiceEvalBaselineHTML, renderVoiceEvalHTML, renderVoiceScenarioEvalHTML, renderVoiceScenarioFixtureEvalHTML, runVoiceScenarioEvals, runVoiceScenarioFixtureEvals, runVoiceSessionEvals } from './evalRoutes';
|
|
7
8
|
export { createVoiceWorkflowContract, createVoiceWorkflowContractHandler, createVoiceWorkflowContractPreset, createVoiceWorkflowScenario, recordVoiceWorkflowContractTrace, validateVoiceWorkflowRouteResult } from './workflowContract';
|
|
@@ -48,6 +49,7 @@ export { resolveVoiceRuntimePreset } from './presets';
|
|
|
48
49
|
export { resolveTurnDetectionConfig, TURN_PROFILE_DEFAULTS } from './turnProfiles';
|
|
49
50
|
export { createVoiceCallReviewFromLiveTelephonyReport, createVoiceCallReviewRecorder, renderVoiceCallReviewHTML, renderVoiceCallReviewMarkdown } from './testing/review';
|
|
50
51
|
export type { VoiceAppKitLink, VoiceAppKitRoutes, VoiceAppKitRoutesOptions, VoiceAppKitStatus, VoiceAppKitStatusOptions, VoiceAppKitStatusReport, VoiceAppKitSurface } from './appKit';
|
|
52
|
+
export type { VoiceBargeInReport, VoiceBargeInRoutesOptions } from './bargeInRoutes';
|
|
51
53
|
export type { VoiceAssistant, VoiceAssistantArtifactPlan, VoiceAssistantExperiment, VoiceAssistantExperimentOptions, VoiceAssistantGuardrailInput, VoiceAssistantGuardrails, VoiceAssistantMemoryLifecycle, VoiceAssistantMemoryLifecycleInput, VoiceAssistantOptions, VoiceAssistantOutputGuardrailInput, VoiceAssistantPreset, VoiceAssistantRunsSummary, VoiceAssistantRunSummary, VoiceAssistantVariant } from './assistant';
|
|
52
54
|
export type { VoiceAssistantHealthFailure, VoiceAssistantHealthHTMLHandlerOptions, VoiceAssistantHealthRoutesOptions, VoiceAssistantHealthSummary, VoiceAssistantHealthSummaryOptions } from './assistantHealth';
|
|
53
55
|
export type { VoiceAssistantMemoryBinding, VoiceAssistantMemoryHandle, VoiceAssistantMemoryOptions, VoiceAssistantMemoryRecord, VoiceAssistantMemoryStore } from './assistantMemory';
|