@absolutejs/voice 0.0.22-beta.473 → 0.0.22-beta.475
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 +101 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +120 -8
- package/dist/monitor.d.ts +12 -2
- package/dist/types.d.ts +15 -0
- package/dist/vue/index.js +30 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,107 @@ Use it when you want Vapi/Retell/Bland-style voice-agent capability, but you wan
|
|
|
8
8
|
|
|
9
9
|
## What's new
|
|
10
10
|
|
|
11
|
+
### 0.0.22-beta.474 · Phase 5 runtime hookup — auto-wire monitor sockets to live sessions
|
|
12
|
+
|
|
13
|
+
The Phase 5 monitor primitive is now first-class in the voice runtime. Pass a `monitor` binding to `voice({...})` and every session opened against the voice plugin auto-registers in the monitor registry, outbound TTS audio auto-fans-out to all listeners, and the close/superseded/session-switch paths deregister automatically. Supervisors connecting to the listen route get a live audio stream without any manual `record.emit()` calls.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { Elysia } from "elysia";
|
|
17
|
+
import {
|
|
18
|
+
createVoiceInMemoryMonitorRegistry,
|
|
19
|
+
createVoiceLiveMonitorRoutes,
|
|
20
|
+
createVoiceMonitorRuntimeBinding,
|
|
21
|
+
voice,
|
|
22
|
+
} from "@absolutejs/voice";
|
|
23
|
+
|
|
24
|
+
const monitorRegistry = createVoiceInMemoryMonitorRegistry();
|
|
25
|
+
|
|
26
|
+
const app = new Elysia()
|
|
27
|
+
.use(
|
|
28
|
+
voice({
|
|
29
|
+
path: "/voice/realtime",
|
|
30
|
+
stt: deepgram({ apiKey: process.env.DEEPGRAM_API_KEY! }),
|
|
31
|
+
tts: elevenlabs({ apiKey: process.env.ELEVENLABS_API_KEY! }),
|
|
32
|
+
onTurn: async (session, turn, api) => {
|
|
33
|
+
// your business logic
|
|
34
|
+
},
|
|
35
|
+
session: sessionStore,
|
|
36
|
+
monitor: createVoiceMonitorRuntimeBinding(monitorRegistry, {
|
|
37
|
+
audioFormat: { channels: 1, container: "raw", encoding: "pcm_s16le", sampleRateHz: 24_000 },
|
|
38
|
+
}),
|
|
39
|
+
}),
|
|
40
|
+
)
|
|
41
|
+
.use(
|
|
42
|
+
createVoiceLiveMonitorRoutes({
|
|
43
|
+
registry: monitorRegistry,
|
|
44
|
+
authenticate: async ({ request }) => await verifySupervisorJWT(request),
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Surface additions:
|
|
50
|
+
- **`createVoiceMonitorRuntimeBinding(registry, { audioFormat?, defaultSource? })`** — returns a `VoiceMonitorRuntimeBinding` you pass to the voice plugin's new `monitor` option. Internally, each session open calls `registerSession({ handle, sessionId })`, audio fans out via `emitAudio()` on every binary `socket.send`, and the close/superseded/session-switch paths call `deregister(reason)`.
|
|
51
|
+
- **`VoicePluginConfig.monitor?: VoiceMonitorRuntimeBinding`** — new optional field on the main voice plugin config.
|
|
52
|
+
- **`VoiceMonitorMutableRegistry.deregister(sessionId, reason?)`** — explicit deregister path so the runtime binding can tear down stale records on re-register without throwing. The `register()`-returned deregister fn now also accepts an optional reason.
|
|
53
|
+
- The runtime binding is **opt-in** — if you don't pass `monitor`, voice behaves exactly as before. No overhead on the audio-send hot path beyond a single `Map.get`.
|
|
54
|
+
|
|
55
|
+
4 new tests cover the runtime binding's register/emit/deregister cycle, no-op-after-deregister, re-registration tear-down, and the audioFormat + defaultSource option threading. Full voice suite now 963 pass / 1 pre-existing fail.
|
|
56
|
+
|
|
57
|
+
### 0.0.22-beta.473 · Phase 5 — live listen + control monitor sockets (Vapi `monitorPlan` parity)
|
|
58
|
+
|
|
59
|
+
Two new WebSocket routes per session that mirror Vapi's `monitorPlan.listenUrl` + `monitorPlan.controlUrl`. Supervisors can subscribe to a live call's outbound audio and send control commands (transfer, hangup, escalate, voicemail, no-answer, plus caller-defined mute/say/inject) without touching the call itself.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { Elysia } from "elysia";
|
|
63
|
+
import {
|
|
64
|
+
buildVoiceMonitorPlan,
|
|
65
|
+
createVoiceInMemoryMonitorRegistry,
|
|
66
|
+
createVoiceLiveMonitorRoutes,
|
|
67
|
+
createVoiceMonitorSession,
|
|
68
|
+
} from "@absolutejs/voice";
|
|
69
|
+
|
|
70
|
+
const registry = createVoiceInMemoryMonitorRegistry();
|
|
71
|
+
|
|
72
|
+
// In your runtime: when a session opens, register it so supervisors can listen.
|
|
73
|
+
const record = createVoiceMonitorSession({ handle, sessionId: handle.id });
|
|
74
|
+
const deregister = registry.register(record);
|
|
75
|
+
// When audio leaves the assistant, fan it out:
|
|
76
|
+
// record.emit({ at: Date.now(), chunk, format, source: 'assistant' });
|
|
77
|
+
// On call end:
|
|
78
|
+
// deregister();
|
|
79
|
+
|
|
80
|
+
const app = new Elysia()
|
|
81
|
+
.use(
|
|
82
|
+
createVoiceLiveMonitorRoutes({
|
|
83
|
+
authenticate: async ({ sessionId, route, request }) =>
|
|
84
|
+
await verifySupervisorJWT(request),
|
|
85
|
+
controlHandlers: {
|
|
86
|
+
say: async ({ message, session }) => {
|
|
87
|
+
await yourTtsRuntime.sayInSession(session.sessionId, message.text);
|
|
88
|
+
return { detail: `Said: ${message.text}`, ok: true, type: "say" };
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
htmlPath: "/voice/monitor",
|
|
92
|
+
registry,
|
|
93
|
+
}),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const plan = buildVoiceMonitorPlan({
|
|
97
|
+
baseUrl: "wss://api.example.com",
|
|
98
|
+
sessionId: handle.id,
|
|
99
|
+
});
|
|
100
|
+
// plan.listenUrl → wss://api.example.com/api/voice/monitor/<sessionId>/listen
|
|
101
|
+
// plan.controlUrl → wss://api.example.com/api/voice/monitor/<sessionId>/control
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Surface summary:
|
|
105
|
+
- **`createVoiceInMemoryMonitorRegistry()`** — `{ register, get, list, emit, emitClose }`. Voice's session runtime (or any caller) wires `register()` on open + the returned deregister on close; `emit()` fans out outbound audio frames; `emitClose()` notifies listeners that the call ended.
|
|
106
|
+
- **`createVoiceLiveMonitorRoutes(options)`** — Elysia plugin that mounts two `.ws()` routes per session: `:sessionId/listen` (read-only outbound audio as binary frames) and `:sessionId/control` (JSON control messages). Default handlers map `transfer`/`hangup`/`escalate`/`voicemail`/`no-answer` onto `VoiceSessionHandle` verbs; `mute`/`say`/`inject` require caller-supplied handlers via `controlHandlers`.
|
|
107
|
+
- **`buildVoiceMonitorPlan(input)`** — Vapi-shaped helper returning `{ listenUrl, controlUrl }` for inclusion in your call-create API response.
|
|
108
|
+
- **Auth hook** — `authenticate?: ({ sessionId, route, request }) => Promise<boolean>` runs at the start of both routes; rejected connections get a 4401 close.
|
|
109
|
+
|
|
110
|
+
This is a **primitive**: wiring voice's existing `activeSessions` runtime into the registry (so audio actually flows from a real call without manual `record.emit()` calls) is the next step and intentionally left out to keep this change additive. Until then, registries built by hand (e.g. from a custom telephony adapter where you control the outbound audio buffer) work out of the box.
|
|
111
|
+
|
|
11
112
|
### 0.0.22-beta.472 · Phase 6 — multilingual STT proof gate
|
|
12
113
|
|
|
13
114
|
`runVoiceMultilingualProof(...)` turns the `voice-fixtures-multilingual` corpus (FLEURS + BSC Catalan-Spanish code-switch + CoSHE Hindi-English code-switch) into a gateable readiness/proof artifact. Buyers evaluating Vapi-replacement can now run any combination of STT adapters against the multilingual corpus and assert per-language WER / pass-rate / term-recall budgets in CI.
|
package/dist/index.d.ts
CHANGED
|
@@ -225,6 +225,6 @@ export { buildVoiceProofPackInput, buildVoiceProofPack, buildVoiceProofPackFromO
|
|
|
225
225
|
export type { VoiceProofPack, VoiceProofPackBuildContext, VoiceProofPackBuildContextOptions, VoiceProofPackBuildTiming, VoiceProofPackEvidence, VoiceProofPackInput, VoiceProofPackInputBuilderLoaderInput, VoiceProofPackInputBuilderOperationsLoaderInput, VoiceProofPackInputBuilderOptions, VoiceProofPackInputBuilderSupportBundle, VoiceProofPackRefreshState, VoiceProofPackRefreshStatus, VoiceProofPackRoutesOptions, VoiceProofPackSection, VoiceProofPackSourceValue, VoiceProofPackStatus, VoiceProofPackStaleWhileRefreshSource, VoiceProofPackStaleWhileRefreshSourceOptions, VoiceProofPackWriteResult, VoiceProofRefreshSnapshot, VoiceProofRefreshSnapshotOptions, } from "./proofPack";
|
|
226
226
|
export { buildVoiceMultilingualProofReadinessCheck, renderVoiceMultilingualProofMarkdown, runVoiceMultilingualProof, } from "./multilingualProof";
|
|
227
227
|
export type { VoiceMultilingualLanguageCode, VoiceMultilingualProofAdapterEntry, VoiceMultilingualProofAdapterReport, VoiceMultilingualProofDefaultThresholds, VoiceMultilingualProofLanguageMetrics, VoiceMultilingualProofLanguageReport, VoiceMultilingualProofLanguageThresholds, VoiceMultilingualProofOptions, VoiceMultilingualProofReadinessCheck, VoiceMultilingualProofReadinessOptions, VoiceMultilingualProofReport, } from "./multilingualProof";
|
|
228
|
-
export { buildVoiceMonitorPlan, createVoiceInMemoryMonitorRegistry, createVoiceLiveMonitorRoutes, createVoiceMonitorSession, } from "./monitor";
|
|
229
|
-
export type { VoiceMonitorAudioEvent, VoiceMonitorAudioSource, VoiceMonitorAuthenticate, VoiceMonitorAuthenticateInput, VoiceMonitorControlAck, VoiceMonitorControlHandler, VoiceMonitorControlHandlerInput, VoiceMonitorControlMessage, VoiceMonitorMutableRegistry, VoiceMonitorPlan, VoiceMonitorPlanInput, VoiceMonitorRegistry, VoiceMonitorRegistryRegisterInput, VoiceLiveMonitorRoutesOptions, VoiceMonitorSessionRecord, } from "./monitor";
|
|
228
|
+
export { buildVoiceMonitorPlan, createVoiceInMemoryMonitorRegistry, createVoiceLiveMonitorRoutes, createVoiceMonitorRuntimeBinding, createVoiceMonitorSession, } from "./monitor";
|
|
229
|
+
export type { VoiceMonitorAudioEvent, VoiceMonitorAudioSource, VoiceMonitorAuthenticate, VoiceMonitorAuthenticateInput, VoiceMonitorControlAck, VoiceMonitorControlHandler, VoiceMonitorControlHandlerInput, VoiceMonitorControlMessage, VoiceMonitorMutableRegistry, VoiceMonitorPlan, VoiceMonitorPlanInput, VoiceMonitorRegistry, VoiceMonitorRegistryRegisterInput, VoiceLiveMonitorRoutesOptions, VoiceMonitorRuntimeBindingOptions, VoiceMonitorSessionRecord, } from "./monitor";
|
|
230
230
|
export * from "./types";
|
package/dist/index.js
CHANGED
|
@@ -6265,6 +6265,7 @@ var voice = (config) => {
|
|
|
6265
6265
|
if (!config.stt && !config.realtime) {
|
|
6266
6266
|
throw new Error("voice requires either an stt or realtime adapter.");
|
|
6267
6267
|
}
|
|
6268
|
+
const monitorBindings = new Map;
|
|
6268
6269
|
const runtime = {
|
|
6269
6270
|
activeSessions: new Map,
|
|
6270
6271
|
logger: resolveLogger(config.logger),
|
|
@@ -6272,6 +6273,57 @@ var voice = (config) => {
|
|
|
6272
6273
|
profileSwitchGuardedSessions: new Set,
|
|
6273
6274
|
socketSessions: new WeakMap
|
|
6274
6275
|
};
|
|
6276
|
+
const monitor = config.monitor;
|
|
6277
|
+
const registerMonitorSession = (sessionId, handle) => {
|
|
6278
|
+
if (!monitor)
|
|
6279
|
+
return;
|
|
6280
|
+
const existing = monitorBindings.get(sessionId);
|
|
6281
|
+
if (existing) {
|
|
6282
|
+
try {
|
|
6283
|
+
existing.deregister("superseded");
|
|
6284
|
+
} catch {}
|
|
6285
|
+
monitorBindings.delete(sessionId);
|
|
6286
|
+
}
|
|
6287
|
+
try {
|
|
6288
|
+
const binding = monitor.registerSession({ handle, sessionId });
|
|
6289
|
+
monitorBindings.set(sessionId, binding);
|
|
6290
|
+
} catch (error) {
|
|
6291
|
+
runtime.logger.warn?.(`[voice] failed to register session "${sessionId}" with monitor runtime: ${error instanceof Error ? error.message : String(error)}`);
|
|
6292
|
+
}
|
|
6293
|
+
};
|
|
6294
|
+
const deregisterMonitorSession = (sessionId, reason) => {
|
|
6295
|
+
const binding = monitorBindings.get(sessionId);
|
|
6296
|
+
if (!binding)
|
|
6297
|
+
return;
|
|
6298
|
+
monitorBindings.delete(sessionId);
|
|
6299
|
+
try {
|
|
6300
|
+
binding.deregister(reason);
|
|
6301
|
+
} catch (error) {
|
|
6302
|
+
runtime.logger.warn?.(`[voice] failed to deregister monitor binding for session "${sessionId}": ${error instanceof Error ? error.message : String(error)}`);
|
|
6303
|
+
}
|
|
6304
|
+
};
|
|
6305
|
+
const buildSocketAdapter = (ws, sessionId) => {
|
|
6306
|
+
if (!monitor)
|
|
6307
|
+
return createSocketAdapter(ws);
|
|
6308
|
+
return {
|
|
6309
|
+
close: async (code, reason) => {
|
|
6310
|
+
ws.close(code, reason);
|
|
6311
|
+
},
|
|
6312
|
+
send: async (data) => {
|
|
6313
|
+
if (typeof data !== "string") {
|
|
6314
|
+
const binding = monitorBindings.get(sessionId);
|
|
6315
|
+
if (binding) {
|
|
6316
|
+
try {
|
|
6317
|
+
binding.emitAudio(data);
|
|
6318
|
+
} catch (error) {
|
|
6319
|
+
runtime.logger.warn?.(`[voice] monitor emitAudio failed for session "${sessionId}": ${error instanceof Error ? error.message : String(error)}`);
|
|
6320
|
+
}
|
|
6321
|
+
}
|
|
6322
|
+
}
|
|
6323
|
+
ws.send(data);
|
|
6324
|
+
}
|
|
6325
|
+
};
|
|
6326
|
+
};
|
|
6275
6327
|
const onTurn = normalizeOnTurn(config.onTurn);
|
|
6276
6328
|
const sessionOptions = resolveSessionOptions(config);
|
|
6277
6329
|
const htmxOptions = config.htmx && typeof config.htmx === "object" ? config.htmx : undefined;
|
|
@@ -6394,6 +6446,7 @@ var voice = (config) => {
|
|
|
6394
6446
|
}
|
|
6395
6447
|
const session = runtime.activeSessions.get(socketState.sessionId);
|
|
6396
6448
|
runtime.activeSessions.delete(socketState.sessionId);
|
|
6449
|
+
deregisterMonitorSession(socketState.sessionId, reason ?? `ws-close-${String(code)}`);
|
|
6397
6450
|
if (session) {
|
|
6398
6451
|
await session.disconnect({
|
|
6399
6452
|
code,
|
|
@@ -6417,6 +6470,7 @@ var voice = (config) => {
|
|
|
6417
6470
|
if (message.type === "close" && current) {
|
|
6418
6471
|
await current.close(message.reason);
|
|
6419
6472
|
runtime.activeSessions.delete(sessionState.sessionId);
|
|
6473
|
+
deregisterMonitorSession(sessionState.sessionId, message.reason);
|
|
6420
6474
|
}
|
|
6421
6475
|
if (message.type === "call_control" && current) {
|
|
6422
6476
|
if (message.action === "transfer") {
|
|
@@ -6459,6 +6513,7 @@ var voice = (config) => {
|
|
|
6459
6513
|
if (currentSession) {
|
|
6460
6514
|
await currentSession.close("session-switch");
|
|
6461
6515
|
runtime.activeSessions.delete(sessionState.sessionId);
|
|
6516
|
+
deregisterMonitorSession(sessionState.sessionId, "session-switch");
|
|
6462
6517
|
}
|
|
6463
6518
|
sessionState.sessionId = message.sessionId;
|
|
6464
6519
|
runtime.socketSessions.set(ws, {
|
|
@@ -6482,8 +6537,10 @@ var voice = (config) => {
|
|
|
6482
6537
|
}
|
|
6483
6538
|
const session = current ?? await createManagedSession(ws, sessionState.sessionId, sessionState.scenarioId ?? undefined);
|
|
6484
6539
|
if (!current) {
|
|
6485
|
-
|
|
6486
|
-
|
|
6540
|
+
const typedSession = session;
|
|
6541
|
+
runtime.activeSessions.set(sessionState.sessionId, typedSession);
|
|
6542
|
+
registerMonitorSession(sessionState.sessionId, typedSession);
|
|
6543
|
+
await session.connect(buildSocketAdapter(ws, sessionState.sessionId));
|
|
6487
6544
|
}
|
|
6488
6545
|
await session.receiveAudio(audio);
|
|
6489
6546
|
},
|
|
@@ -6493,10 +6550,13 @@ var voice = (config) => {
|
|
|
6493
6550
|
if (existing) {
|
|
6494
6551
|
await existing.close("superseded");
|
|
6495
6552
|
runtime.activeSessions.delete(sessionState.sessionId);
|
|
6553
|
+
deregisterMonitorSession(sessionState.sessionId, "superseded");
|
|
6496
6554
|
}
|
|
6497
6555
|
const session = await createManagedSession(ws, sessionState.sessionId, sessionState.scenarioId ?? undefined);
|
|
6498
|
-
|
|
6499
|
-
|
|
6556
|
+
const typedSession = session;
|
|
6557
|
+
runtime.activeSessions.set(sessionState.sessionId, typedSession);
|
|
6558
|
+
registerMonitorSession(sessionState.sessionId, typedSession);
|
|
6559
|
+
await session.connect(buildSocketAdapter(ws, sessionState.sessionId));
|
|
6500
6560
|
}
|
|
6501
6561
|
}).use(htmxRoutes());
|
|
6502
6562
|
};
|
|
@@ -44501,7 +44561,15 @@ var createVoiceMonitorSession = (input) => {
|
|
|
44501
44561
|
};
|
|
44502
44562
|
var createVoiceInMemoryMonitorRegistry = () => {
|
|
44503
44563
|
const records = new Map;
|
|
44564
|
+
const deregister = (sessionId, reason) => {
|
|
44565
|
+
const existing = records.get(sessionId);
|
|
44566
|
+
if (!existing)
|
|
44567
|
+
return;
|
|
44568
|
+
records.delete(sessionId);
|
|
44569
|
+
existing.emitClose(reason ?? "deregistered");
|
|
44570
|
+
};
|
|
44504
44571
|
return {
|
|
44572
|
+
deregister,
|
|
44505
44573
|
emit: (sessionId, event) => {
|
|
44506
44574
|
records.get(sessionId)?.emit(event);
|
|
44507
44575
|
},
|
|
@@ -44525,10 +44593,7 @@ var createVoiceInMemoryMonitorRegistry = () => {
|
|
|
44525
44593
|
record.onClose((reason) => wrapped.emitClose(reason));
|
|
44526
44594
|
}
|
|
44527
44595
|
records.set(record.sessionId, wrapped);
|
|
44528
|
-
return () =>
|
|
44529
|
-
records.delete(record.sessionId);
|
|
44530
|
-
wrapped.emitClose("deregistered");
|
|
44531
|
-
};
|
|
44596
|
+
return (reason) => deregister(record.sessionId, reason);
|
|
44532
44597
|
}
|
|
44533
44598
|
};
|
|
44534
44599
|
};
|
|
@@ -44665,6 +44730,52 @@ var buildVoiceMonitorPlan = (input) => {
|
|
|
44665
44730
|
listenUrl: `${baseUrl}${substituteSessionId(listenTemplate, input.sessionId)}`
|
|
44666
44731
|
};
|
|
44667
44732
|
};
|
|
44733
|
+
var DEFAULT_RUNTIME_AUDIO_FORMAT = {
|
|
44734
|
+
channels: 1,
|
|
44735
|
+
container: "raw",
|
|
44736
|
+
encoding: "pcm_s16le",
|
|
44737
|
+
sampleRateHz: 16000
|
|
44738
|
+
};
|
|
44739
|
+
var toUint8 = (chunk) => chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);
|
|
44740
|
+
var createVoiceMonitorRuntimeBinding = (registry, options = {}) => {
|
|
44741
|
+
const audioFormat = options.audioFormat ?? DEFAULT_RUNTIME_AUDIO_FORMAT;
|
|
44742
|
+
const defaultSource = options.defaultSource ?? "assistant";
|
|
44743
|
+
return {
|
|
44744
|
+
registerSession: (input) => {
|
|
44745
|
+
registry.deregister(input.sessionId, "superseded");
|
|
44746
|
+
const record = createVoiceMonitorSession({
|
|
44747
|
+
handle: input.handle,
|
|
44748
|
+
metadata: input.metadata,
|
|
44749
|
+
sessionId: input.sessionId
|
|
44750
|
+
});
|
|
44751
|
+
const deregisterFromRegistry = registry.register(record);
|
|
44752
|
+
let closed = false;
|
|
44753
|
+
return {
|
|
44754
|
+
deregister: (reason) => {
|
|
44755
|
+
if (closed)
|
|
44756
|
+
return;
|
|
44757
|
+
closed = true;
|
|
44758
|
+
try {
|
|
44759
|
+
deregisterFromRegistry(reason);
|
|
44760
|
+
} catch {}
|
|
44761
|
+
},
|
|
44762
|
+
emitAudio: (chunk, opts) => {
|
|
44763
|
+
if (closed)
|
|
44764
|
+
return;
|
|
44765
|
+
const bytes = toUint8(chunk);
|
|
44766
|
+
if (bytes.byteLength === 0)
|
|
44767
|
+
return;
|
|
44768
|
+
record.emit({
|
|
44769
|
+
at: Date.now(),
|
|
44770
|
+
chunk: bytes,
|
|
44771
|
+
format: audioFormat,
|
|
44772
|
+
source: opts?.source ?? defaultSource
|
|
44773
|
+
});
|
|
44774
|
+
}
|
|
44775
|
+
};
|
|
44776
|
+
}
|
|
44777
|
+
};
|
|
44778
|
+
};
|
|
44668
44779
|
var resolveSessionId3 = (ws) => {
|
|
44669
44780
|
const params = ws.data?.params;
|
|
44670
44781
|
if (!params)
|
|
@@ -45358,6 +45469,7 @@ export {
|
|
|
45358
45469
|
createVoiceObservabilityExportReplayRoutes,
|
|
45359
45470
|
createVoiceMonitorWebhookNotifier,
|
|
45360
45471
|
createVoiceMonitorSession,
|
|
45472
|
+
createVoiceMonitorRuntimeBinding,
|
|
45361
45473
|
createVoiceMonitorRunnerRoutes,
|
|
45362
45474
|
createVoiceMonitorRunner,
|
|
45363
45475
|
createVoiceMonitorRoutes,
|
package/dist/monitor.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Elysia } from "elysia";
|
|
2
|
-
import type { AudioFormat, VoiceSessionHandle, VoiceSessionRecord } from "./types";
|
|
2
|
+
import type { AudioFormat, VoiceMonitorRuntimeBinding, VoiceSessionHandle, VoiceSessionRecord } from "./types";
|
|
3
3
|
export type VoiceMonitorAudioSource = "assistant" | "caller" | (string & {});
|
|
4
4
|
export type VoiceMonitorAudioEvent = {
|
|
5
5
|
at: number;
|
|
@@ -23,7 +23,12 @@ export type VoiceMonitorRegistry = {
|
|
|
23
23
|
export type VoiceMonitorMutableRegistry = VoiceMonitorRegistry & {
|
|
24
24
|
emit: (sessionId: string, event: VoiceMonitorAudioEvent) => void;
|
|
25
25
|
emitClose: (sessionId: string, reason?: string) => void;
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Deregister a session by id. No-op if the id isn't registered. The
|
|
28
|
+
* `reason` flows into the close fan-out exactly once.
|
|
29
|
+
*/
|
|
30
|
+
deregister: (sessionId: string, reason?: string) => void;
|
|
31
|
+
register: (record: VoiceMonitorSessionRecord) => (reason?: string) => void;
|
|
27
32
|
};
|
|
28
33
|
export type VoiceMonitorRegistryRegisterInput = {
|
|
29
34
|
handle: VoiceSessionHandle<unknown, VoiceSessionRecord, unknown>;
|
|
@@ -108,6 +113,11 @@ export type VoiceMonitorPlan = {
|
|
|
108
113
|
listenUrl: string;
|
|
109
114
|
};
|
|
110
115
|
export declare const buildVoiceMonitorPlan: (input: VoiceMonitorPlanInput) => VoiceMonitorPlan;
|
|
116
|
+
export type VoiceMonitorRuntimeBindingOptions = {
|
|
117
|
+
audioFormat?: AudioFormat;
|
|
118
|
+
defaultSource?: VoiceMonitorAudioSource;
|
|
119
|
+
};
|
|
120
|
+
export declare const createVoiceMonitorRuntimeBinding: (registry: VoiceMonitorMutableRegistry, options?: VoiceMonitorRuntimeBindingOptions) => VoiceMonitorRuntimeBinding;
|
|
111
121
|
export declare const createVoiceLiveMonitorRoutes: (options: VoiceLiveMonitorRoutesOptions) => Elysia<"", {
|
|
112
122
|
decorator: {};
|
|
113
123
|
store: {};
|
package/dist/types.d.ts
CHANGED
|
@@ -411,6 +411,20 @@ export type VoiceSocket = {
|
|
|
411
411
|
send: (data: string | Uint8Array | ArrayBuffer) => void | Promise<void>;
|
|
412
412
|
close: (code?: number, reason?: string) => void | Promise<void>;
|
|
413
413
|
};
|
|
414
|
+
export type VoiceMonitorRuntimeSessionBinding = {
|
|
415
|
+
deregister: (reason?: string) => void;
|
|
416
|
+
emitAudio: (chunk: Uint8Array | ArrayBuffer, options?: {
|
|
417
|
+
source?: "assistant" | "caller" | (string & {});
|
|
418
|
+
}) => void;
|
|
419
|
+
};
|
|
420
|
+
export type VoiceMonitorRuntimeRegisterInput = {
|
|
421
|
+
handle: VoiceSessionHandle<unknown, VoiceSessionRecord, unknown>;
|
|
422
|
+
metadata?: Record<string, unknown>;
|
|
423
|
+
sessionId: string;
|
|
424
|
+
};
|
|
425
|
+
export type VoiceMonitorRuntimeBinding = {
|
|
426
|
+
registerSession: (input: VoiceMonitorRuntimeRegisterInput) => VoiceMonitorRuntimeSessionBinding;
|
|
427
|
+
};
|
|
414
428
|
export type VoiceSessionHandle<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
|
|
415
429
|
id: string;
|
|
416
430
|
connect: (socket: VoiceSocket) => Promise<void>;
|
|
@@ -679,6 +693,7 @@ export type VoicePluginConfig<TContext = unknown, TSession extends VoiceSessionR
|
|
|
679
693
|
handoff?: VoiceHandoffConfig<TContext, TSession, TResult>;
|
|
680
694
|
ops?: VoiceRuntimeOpsConfig<TContext, TSession, TResult>;
|
|
681
695
|
liveOps?: VoiceLiveOpsRuntimeConfig;
|
|
696
|
+
monitor?: VoiceMonitorRuntimeBinding;
|
|
682
697
|
profileSwitchGuard?: VoicePluginProfileSwitchGuardConfig<TContext, TSession, TResult>;
|
|
683
698
|
trace?: VoiceTraceEventStore;
|
|
684
699
|
} & VoiceRouteConfig<TContext, TSession, TResult>;
|
package/dist/vue/index.js
CHANGED
|
@@ -278,7 +278,7 @@ var defineVoiceOpsStatusElement = (tagName = "absolute-voice-ops-status") => {
|
|
|
278
278
|
};
|
|
279
279
|
|
|
280
280
|
// src/vue/useVoiceOpsStatus.ts
|
|
281
|
-
import { onUnmounted, ref, shallowRef } from "vue";
|
|
281
|
+
import { onMounted, onUnmounted, ref, shallowRef } from "vue";
|
|
282
282
|
function useVoiceOpsStatus(path = "/api/voice/ops-status", options = {}) {
|
|
283
283
|
const store = createVoiceOpsStatusStore(path, options);
|
|
284
284
|
const error = ref(null);
|
|
@@ -294,9 +294,9 @@ function useVoiceOpsStatus(path = "/api/voice/ops-status", options = {}) {
|
|
|
294
294
|
};
|
|
295
295
|
const unsubscribe = store.subscribe(sync);
|
|
296
296
|
sync();
|
|
297
|
-
|
|
297
|
+
onMounted(() => {
|
|
298
298
|
store.refresh().catch(() => {});
|
|
299
|
-
}
|
|
299
|
+
});
|
|
300
300
|
onUnmounted(() => {
|
|
301
301
|
unsubscribe();
|
|
302
302
|
store.close();
|
|
@@ -1012,7 +1012,7 @@ var defineVoiceDeliveryRuntimeElement = (tagName = "absolute-voice-delivery-runt
|
|
|
1012
1012
|
};
|
|
1013
1013
|
|
|
1014
1014
|
// src/vue/useVoiceDeliveryRuntime.ts
|
|
1015
|
-
import { onUnmounted as onUnmounted3, ref as ref3, shallowRef as shallowRef3 } from "vue";
|
|
1015
|
+
import { onMounted as onMounted2, onUnmounted as onUnmounted3, ref as ref3, shallowRef as shallowRef3 } from "vue";
|
|
1016
1016
|
function useVoiceDeliveryRuntime(path = "/api/voice-delivery-runtime", options = {}) {
|
|
1017
1017
|
const store = createVoiceDeliveryRuntimeStore(path, options);
|
|
1018
1018
|
const actionError = ref3(null);
|
|
@@ -1032,9 +1032,9 @@ function useVoiceDeliveryRuntime(path = "/api/voice-delivery-runtime", options =
|
|
|
1032
1032
|
};
|
|
1033
1033
|
const unsubscribe = store.subscribe(sync);
|
|
1034
1034
|
sync();
|
|
1035
|
-
|
|
1035
|
+
onMounted2(() => {
|
|
1036
1036
|
store.refresh().catch(() => {});
|
|
1037
|
-
}
|
|
1037
|
+
});
|
|
1038
1038
|
onUnmounted3(() => {
|
|
1039
1039
|
unsubscribe();
|
|
1040
1040
|
store.close();
|
|
@@ -1133,7 +1133,7 @@ var VoiceDeliveryRuntime = defineComponent3({
|
|
|
1133
1133
|
import { defineComponent as defineComponent4, h as h4 } from "vue";
|
|
1134
1134
|
|
|
1135
1135
|
// src/vue/useVoicePlatformCoverage.ts
|
|
1136
|
-
import { onUnmounted as onUnmounted4, ref as ref4, shallowRef as shallowRef4 } from "vue";
|
|
1136
|
+
import { onMounted as onMounted3, onUnmounted as onUnmounted4, ref as ref4, shallowRef as shallowRef4 } from "vue";
|
|
1137
1137
|
|
|
1138
1138
|
// src/client/platformCoverage.ts
|
|
1139
1139
|
var fetchVoicePlatformCoverage = async (path = "/api/voice/platform-coverage", options = {}) => {
|
|
@@ -1230,9 +1230,9 @@ function useVoicePlatformCoverage(path = "/api/voice/platform-coverage", options
|
|
|
1230
1230
|
};
|
|
1231
1231
|
const unsubscribe = store.subscribe(sync);
|
|
1232
1232
|
sync();
|
|
1233
|
-
|
|
1233
|
+
onMounted3(() => {
|
|
1234
1234
|
store.refresh().catch(() => {});
|
|
1235
|
-
}
|
|
1235
|
+
});
|
|
1236
1236
|
onUnmounted4(() => {
|
|
1237
1237
|
unsubscribe();
|
|
1238
1238
|
store.close();
|
|
@@ -6234,7 +6234,7 @@ var defineVoiceProofTrendsElement = (tagName = "absolute-voice-proof-trends") =>
|
|
|
6234
6234
|
};
|
|
6235
6235
|
|
|
6236
6236
|
// src/vue/useVoiceProofTrends.ts
|
|
6237
|
-
import { onUnmounted as onUnmounted5, ref as ref5, shallowRef as shallowRef5 } from "vue";
|
|
6237
|
+
import { onMounted as onMounted4, onUnmounted as onUnmounted5, ref as ref5, shallowRef as shallowRef5 } from "vue";
|
|
6238
6238
|
function useVoiceProofTrends(path = "/api/voice/proof-trends", options = {}) {
|
|
6239
6239
|
const store = createVoiceProofTrendsStore(path, options);
|
|
6240
6240
|
const error = ref5(null);
|
|
@@ -6250,9 +6250,9 @@ function useVoiceProofTrends(path = "/api/voice/proof-trends", options = {}) {
|
|
|
6250
6250
|
};
|
|
6251
6251
|
const unsubscribe = store.subscribe(sync);
|
|
6252
6252
|
sync();
|
|
6253
|
-
|
|
6253
|
+
onMounted4(() => {
|
|
6254
6254
|
store.refresh().catch(() => {});
|
|
6255
|
-
}
|
|
6255
|
+
});
|
|
6256
6256
|
onUnmounted5(() => {
|
|
6257
6257
|
unsubscribe();
|
|
6258
6258
|
store.close();
|
|
@@ -6515,7 +6515,7 @@ var defineVoiceReconnectProfileEvidenceElement = (tagName = "absolute-voice-reco
|
|
|
6515
6515
|
};
|
|
6516
6516
|
|
|
6517
6517
|
// src/vue/useVoiceReconnectProfileEvidence.ts
|
|
6518
|
-
import { onUnmounted as onUnmounted6, ref as ref6, shallowRef as shallowRef6 } from "vue";
|
|
6518
|
+
import { onMounted as onMounted5, onUnmounted as onUnmounted6, ref as ref6, shallowRef as shallowRef6 } from "vue";
|
|
6519
6519
|
function useVoiceReconnectProfileEvidence(path = "/api/voice/reconnect-profile-evidence", options = {}) {
|
|
6520
6520
|
const store = createVoiceReconnectProfileEvidenceStore(path, options);
|
|
6521
6521
|
const error = ref6(null);
|
|
@@ -6531,9 +6531,9 @@ function useVoiceReconnectProfileEvidence(path = "/api/voice/reconnect-profile-e
|
|
|
6531
6531
|
};
|
|
6532
6532
|
const unsubscribe = store.subscribe(sync);
|
|
6533
6533
|
sync();
|
|
6534
|
-
|
|
6534
|
+
onMounted5(() => {
|
|
6535
6535
|
store.refresh().catch(() => {});
|
|
6536
|
-
}
|
|
6536
|
+
});
|
|
6537
6537
|
onUnmounted6(() => {
|
|
6538
6538
|
unsubscribe();
|
|
6539
6539
|
store.close();
|
|
@@ -7583,7 +7583,7 @@ var defineVoiceReadinessFailuresElement = (tagName = "absolute-voice-readiness-f
|
|
|
7583
7583
|
};
|
|
7584
7584
|
|
|
7585
7585
|
// src/vue/useVoiceReadinessFailures.ts
|
|
7586
|
-
import { onBeforeUnmount as onBeforeUnmount2, readonly, ref as ref8 } from "vue";
|
|
7586
|
+
import { onMounted as onMounted6, onBeforeUnmount as onBeforeUnmount2, readonly, ref as ref8 } from "vue";
|
|
7587
7587
|
var useVoiceReadinessFailures = (path = "/api/production-readiness", options = {}) => {
|
|
7588
7588
|
const store = createVoiceReadinessFailuresStore(path, options);
|
|
7589
7589
|
const error = ref8(null);
|
|
@@ -7599,9 +7599,9 @@ var useVoiceReadinessFailures = (path = "/api/production-readiness", options = {
|
|
|
7599
7599
|
};
|
|
7600
7600
|
const unsubscribe = store.subscribe(sync);
|
|
7601
7601
|
sync();
|
|
7602
|
-
|
|
7602
|
+
onMounted6(() => {
|
|
7603
7603
|
store.refresh().catch(() => {});
|
|
7604
|
-
}
|
|
7604
|
+
});
|
|
7605
7605
|
onBeforeUnmount2(() => {
|
|
7606
7606
|
unsubscribe();
|
|
7607
7607
|
store.close();
|
|
@@ -9172,7 +9172,7 @@ var VoiceRoutingStatus = defineComponent15({
|
|
|
9172
9172
|
}
|
|
9173
9173
|
});
|
|
9174
9174
|
// src/vue/useVoiceAgentSquadStatus.ts
|
|
9175
|
-
import { onUnmounted as onUnmounted14, ref as ref12, shallowRef as shallowRef13 } from "vue";
|
|
9175
|
+
import { onMounted as onMounted7, onUnmounted as onUnmounted14, ref as ref12, shallowRef as shallowRef13 } from "vue";
|
|
9176
9176
|
|
|
9177
9177
|
// src/client/traceTimeline.ts
|
|
9178
9178
|
var fetchVoiceTraceTimeline = async (path = "/api/voice-traces", options = {}) => {
|
|
@@ -9346,9 +9346,9 @@ function useVoiceAgentSquadStatus(path = "/api/voice-traces", options = {}) {
|
|
|
9346
9346
|
};
|
|
9347
9347
|
const unsubscribe = store.subscribe(sync);
|
|
9348
9348
|
sync();
|
|
9349
|
-
|
|
9349
|
+
onMounted7(() => {
|
|
9350
9350
|
store.refresh().catch(() => {});
|
|
9351
|
-
}
|
|
9351
|
+
});
|
|
9352
9352
|
onUnmounted14(() => {
|
|
9353
9353
|
unsubscribe();
|
|
9354
9354
|
store.close();
|
|
@@ -9978,7 +9978,7 @@ function useVoiceSessionObservability(path = "/api/voice/session-observability/l
|
|
|
9978
9978
|
};
|
|
9979
9979
|
}
|
|
9980
9980
|
// src/vue/useVoiceProfileComparison.ts
|
|
9981
|
-
import { onUnmounted as onUnmounted18, ref as ref14, shallowRef as shallowRef17 } from "vue";
|
|
9981
|
+
import { onMounted as onMounted8, onUnmounted as onUnmounted18, ref as ref14, shallowRef as shallowRef17 } from "vue";
|
|
9982
9982
|
|
|
9983
9983
|
// src/client/profileComparison.ts
|
|
9984
9984
|
var fetchVoiceProfileComparison = async (path = "/api/voice/real-call-profile-history", options = {}) => {
|
|
@@ -10071,9 +10071,9 @@ function useVoiceProfileComparison(path = "/api/voice/real-call-profile-history"
|
|
|
10071
10071
|
};
|
|
10072
10072
|
const unsubscribe = store.subscribe(sync);
|
|
10073
10073
|
sync();
|
|
10074
|
-
|
|
10074
|
+
onMounted8(() => {
|
|
10075
10075
|
store.refresh().catch(() => {});
|
|
10076
|
-
}
|
|
10076
|
+
});
|
|
10077
10077
|
onUnmounted18(() => {
|
|
10078
10078
|
unsubscribe();
|
|
10079
10079
|
store.close();
|
|
@@ -10207,7 +10207,7 @@ function useVoiceLiveOps(options = {}) {
|
|
|
10207
10207
|
};
|
|
10208
10208
|
}
|
|
10209
10209
|
// src/vue/useVoiceCampaignDialerProof.ts
|
|
10210
|
-
import { onUnmounted as onUnmounted20, shallowRef as shallowRef19 } from "vue";
|
|
10210
|
+
import { onMounted as onMounted9, onUnmounted as onUnmounted20, shallowRef as shallowRef19 } from "vue";
|
|
10211
10211
|
|
|
10212
10212
|
// src/client/campaignDialerProof.ts
|
|
10213
10213
|
var fetchVoiceCampaignDialerProofStatus = async (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
@@ -10345,9 +10345,9 @@ function useVoiceCampaignDialerProof(path = "/api/voice/campaigns/dialer-proof",
|
|
|
10345
10345
|
};
|
|
10346
10346
|
const unsubscribe = store.subscribe(sync);
|
|
10347
10347
|
sync();
|
|
10348
|
-
|
|
10348
|
+
onMounted9(() => {
|
|
10349
10349
|
store.refresh().catch(() => {});
|
|
10350
|
-
}
|
|
10350
|
+
});
|
|
10351
10351
|
onUnmounted20(() => {
|
|
10352
10352
|
unsubscribe();
|
|
10353
10353
|
store.close();
|
|
@@ -11898,7 +11898,7 @@ function useVoiceTraceTimeline(path = "/api/voice-traces", options = {}) {
|
|
|
11898
11898
|
};
|
|
11899
11899
|
}
|
|
11900
11900
|
// src/vue/useVoiceWorkflowStatus.ts
|
|
11901
|
-
import { onUnmounted as onUnmounted24, ref as ref19, shallowRef as shallowRef23 } from "vue";
|
|
11901
|
+
import { onMounted as onMounted10, onUnmounted as onUnmounted24, ref as ref19, shallowRef as shallowRef23 } from "vue";
|
|
11902
11902
|
|
|
11903
11903
|
// src/client/workflowStatus.ts
|
|
11904
11904
|
var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
|
|
@@ -11995,9 +11995,9 @@ function useVoiceWorkflowStatus(path = "/evals/scenarios/json", options = {}) {
|
|
|
11995
11995
|
};
|
|
11996
11996
|
const unsubscribe = store.subscribe(sync);
|
|
11997
11997
|
sync();
|
|
11998
|
-
|
|
11998
|
+
onMounted10(() => {
|
|
11999
11999
|
store.refresh().catch(() => {});
|
|
12000
|
-
}
|
|
12000
|
+
});
|
|
12001
12001
|
onUnmounted24(() => {
|
|
12002
12002
|
unsubscribe();
|
|
12003
12003
|
store.close();
|