@absolutejs/voice 0.0.22-beta.126 → 0.0.22-beta.128
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 +255 -26
- package/dist/agent.d.ts +5 -0
- package/dist/angular/index.d.ts +1 -1
- package/dist/angular/index.js +16 -16
- package/dist/angular/voice-ops-status.service.d.ts +12 -0
- package/dist/audit.d.ts +128 -0
- package/dist/auditDeliveryRoutes.d.ts +85 -0
- package/dist/auditExport.d.ts +34 -0
- package/dist/auditRoutes.d.ts +66 -0
- package/dist/auditSinks.d.ts +133 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +11 -11
- package/dist/client/opsStatus.d.ts +19 -0
- package/dist/client/opsStatusWidget.d.ts +7 -7
- package/dist/dataControl.d.ts +47 -0
- package/dist/demoReadyRoutes.d.ts +98 -0
- package/dist/fileStore.d.ts +8 -2
- package/dist/index.d.ts +27 -6
- package/dist/index.js +15193 -12626
- package/dist/openaiRealtime.d.ts +27 -0
- package/dist/opsStatus.d.ts +65 -0
- package/dist/opsStatusRoutes.d.ts +33 -0
- package/dist/phoneAgent.d.ts +4 -0
- package/dist/phoneAgentProductionSmoke.d.ts +115 -0
- package/dist/postgresStore.d.ts +8 -2
- package/dist/productionReadiness.d.ts +82 -0
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +16 -16
- package/dist/react/useVoiceOpsStatus.d.ts +8 -0
- package/dist/sqliteStore.d.ts +8 -2
- package/dist/svelte/createVoiceOpsStatus.d.ts +2 -2
- package/dist/svelte/index.d.ts +0 -1
- package/dist/svelte/index.js +72 -75
- package/dist/telephony/twilio.d.ts +3 -2
- package/dist/testing/index.js +74 -21
- package/dist/traceDeliveryRoutes.d.ts +86 -0
- package/dist/types.d.ts +6 -2
- package/dist/vue/index.d.ts +1 -1
- package/dist/vue/index.js +15 -15
- package/dist/vue/useVoiceOpsStatus.d.ts +9 -0
- package/package.json +1 -1
- package/dist/angular/voice-app-kit-status.service.d.ts +0 -12
- package/dist/appKit.d.ts +0 -100
- package/dist/client/appKitStatus.d.ts +0 -19
- package/dist/react/useVoiceAppKitStatus.d.ts +0 -8
- package/dist/svelte/createVoiceAppKitStatus.d.ts +0 -8
- package/dist/vue/useVoiceAppKitStatus.d.ts +0 -9
package/dist/svelte/index.js
CHANGED
|
@@ -69,16 +69,24 @@ var __decorateElement = (array, flags, name, decorators, target, extra) => {
|
|
|
69
69
|
return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
-
// src/client/
|
|
73
|
-
var
|
|
72
|
+
// src/client/campaignDialerProof.ts
|
|
73
|
+
var fetchVoiceCampaignDialerProofStatus = async (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
74
74
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
75
75
|
const response = await fetchImpl(path);
|
|
76
76
|
if (!response.ok) {
|
|
77
|
-
throw new Error(`Voice
|
|
77
|
+
throw new Error(`Voice campaign dialer proof status failed: HTTP ${response.status}`);
|
|
78
78
|
}
|
|
79
79
|
return await response.json();
|
|
80
80
|
};
|
|
81
|
-
var
|
|
81
|
+
var runVoiceCampaignDialerProofAction = async (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
82
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
83
|
+
const response = await fetchImpl(path, { method: "POST" });
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
throw new Error(`Voice campaign dialer proof failed: HTTP ${response.status}`);
|
|
86
|
+
}
|
|
87
|
+
return await response.json();
|
|
88
|
+
};
|
|
89
|
+
var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
82
90
|
const listeners = new Set;
|
|
83
91
|
let closed = false;
|
|
84
92
|
let timer;
|
|
@@ -93,20 +101,50 @@ var createVoiceAppKitStatusStore = (path = "/app-kit/status", options = {}) => {
|
|
|
93
101
|
};
|
|
94
102
|
const refresh = async () => {
|
|
95
103
|
if (closed) {
|
|
96
|
-
return snapshot.
|
|
104
|
+
return snapshot.status;
|
|
97
105
|
}
|
|
98
|
-
snapshot = {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
107
|
+
emit();
|
|
108
|
+
try {
|
|
109
|
+
const status = await fetchVoiceCampaignDialerProofStatus(path, options);
|
|
110
|
+
snapshot = {
|
|
111
|
+
...snapshot,
|
|
112
|
+
error: null,
|
|
113
|
+
isLoading: false,
|
|
114
|
+
status,
|
|
115
|
+
updatedAt: Date.now()
|
|
116
|
+
};
|
|
117
|
+
emit();
|
|
118
|
+
return status;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
snapshot = {
|
|
121
|
+
...snapshot,
|
|
122
|
+
error: error instanceof Error ? error.message : String(error),
|
|
123
|
+
isLoading: false
|
|
124
|
+
};
|
|
125
|
+
emit();
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const runProof = async () => {
|
|
130
|
+
const runPath = options.runPath ?? snapshot.status?.runPath ?? path;
|
|
131
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
103
132
|
emit();
|
|
104
133
|
try {
|
|
105
|
-
const report = await
|
|
134
|
+
const report = await runVoiceCampaignDialerProofAction(runPath, options);
|
|
106
135
|
snapshot = {
|
|
136
|
+
...snapshot,
|
|
107
137
|
error: null,
|
|
108
138
|
isLoading: false,
|
|
109
139
|
report,
|
|
140
|
+
status: {
|
|
141
|
+
generatedAt: Date.now(),
|
|
142
|
+
mode: report.mode,
|
|
143
|
+
ok: report.ok,
|
|
144
|
+
providers: report.providers.map((provider) => provider.provider),
|
|
145
|
+
runPath,
|
|
146
|
+
safe: true
|
|
147
|
+
},
|
|
110
148
|
updatedAt: Date.now()
|
|
111
149
|
};
|
|
112
150
|
emit();
|
|
@@ -129,7 +167,7 @@ var createVoiceAppKitStatusStore = (path = "/app-kit/status", options = {}) => {
|
|
|
129
167
|
}
|
|
130
168
|
listeners.clear();
|
|
131
169
|
};
|
|
132
|
-
if (
|
|
170
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
133
171
|
timer = setInterval(() => {
|
|
134
172
|
refresh().catch(() => {});
|
|
135
173
|
}, options.intervalMs);
|
|
@@ -139,6 +177,7 @@ var createVoiceAppKitStatusStore = (path = "/app-kit/status", options = {}) => {
|
|
|
139
177
|
getServerSnapshot: () => snapshot,
|
|
140
178
|
getSnapshot: () => snapshot,
|
|
141
179
|
refresh,
|
|
180
|
+
runProof,
|
|
142
181
|
subscribe: (listener) => {
|
|
143
182
|
listeners.add(listener);
|
|
144
183
|
return () => {
|
|
@@ -148,26 +187,18 @@ var createVoiceAppKitStatusStore = (path = "/app-kit/status", options = {}) => {
|
|
|
148
187
|
};
|
|
149
188
|
};
|
|
150
189
|
|
|
151
|
-
// src/svelte/
|
|
152
|
-
var
|
|
153
|
-
// src/client/
|
|
154
|
-
var
|
|
190
|
+
// src/svelte/createVoiceCampaignDialerProof.ts
|
|
191
|
+
var createVoiceCampaignDialerProof = (path = "/api/voice/campaigns/dialer-proof", options = {}) => createVoiceCampaignDialerProofStore(path, options);
|
|
192
|
+
// src/client/opsStatus.ts
|
|
193
|
+
var fetchVoiceOpsStatus = async (path = "/api/voice/ops-status", options = {}) => {
|
|
155
194
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
156
195
|
const response = await fetchImpl(path);
|
|
157
196
|
if (!response.ok) {
|
|
158
|
-
throw new Error(`Voice
|
|
197
|
+
throw new Error(`Voice ops status failed: HTTP ${response.status}`);
|
|
159
198
|
}
|
|
160
199
|
return await response.json();
|
|
161
200
|
};
|
|
162
|
-
var
|
|
163
|
-
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
164
|
-
const response = await fetchImpl(path, { method: "POST" });
|
|
165
|
-
if (!response.ok) {
|
|
166
|
-
throw new Error(`Voice campaign dialer proof failed: HTTP ${response.status}`);
|
|
167
|
-
}
|
|
168
|
-
return await response.json();
|
|
169
|
-
};
|
|
170
|
-
var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
|
|
201
|
+
var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) => {
|
|
171
202
|
const listeners = new Set;
|
|
172
203
|
let closed = false;
|
|
173
204
|
let timer;
|
|
@@ -182,50 +213,20 @@ var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-p
|
|
|
182
213
|
};
|
|
183
214
|
const refresh = async () => {
|
|
184
215
|
if (closed) {
|
|
185
|
-
return snapshot.
|
|
186
|
-
}
|
|
187
|
-
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
188
|
-
emit();
|
|
189
|
-
try {
|
|
190
|
-
const status = await fetchVoiceCampaignDialerProofStatus(path, options);
|
|
191
|
-
snapshot = {
|
|
192
|
-
...snapshot,
|
|
193
|
-
error: null,
|
|
194
|
-
isLoading: false,
|
|
195
|
-
status,
|
|
196
|
-
updatedAt: Date.now()
|
|
197
|
-
};
|
|
198
|
-
emit();
|
|
199
|
-
return status;
|
|
200
|
-
} catch (error) {
|
|
201
|
-
snapshot = {
|
|
202
|
-
...snapshot,
|
|
203
|
-
error: error instanceof Error ? error.message : String(error),
|
|
204
|
-
isLoading: false
|
|
205
|
-
};
|
|
206
|
-
emit();
|
|
207
|
-
throw error;
|
|
216
|
+
return snapshot.report;
|
|
208
217
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
218
|
+
snapshot = {
|
|
219
|
+
...snapshot,
|
|
220
|
+
error: null,
|
|
221
|
+
isLoading: true
|
|
222
|
+
};
|
|
213
223
|
emit();
|
|
214
224
|
try {
|
|
215
|
-
const report = await
|
|
225
|
+
const report = await fetchVoiceOpsStatus(path, options);
|
|
216
226
|
snapshot = {
|
|
217
|
-
...snapshot,
|
|
218
227
|
error: null,
|
|
219
228
|
isLoading: false,
|
|
220
229
|
report,
|
|
221
|
-
status: {
|
|
222
|
-
generatedAt: Date.now(),
|
|
223
|
-
mode: report.mode,
|
|
224
|
-
ok: report.ok,
|
|
225
|
-
providers: report.providers.map((provider) => provider.provider),
|
|
226
|
-
runPath,
|
|
227
|
-
safe: true
|
|
228
|
-
},
|
|
229
230
|
updatedAt: Date.now()
|
|
230
231
|
};
|
|
231
232
|
emit();
|
|
@@ -248,7 +249,7 @@ var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-p
|
|
|
248
249
|
}
|
|
249
250
|
listeners.clear();
|
|
250
251
|
};
|
|
251
|
-
if (options.intervalMs && options.intervalMs > 0) {
|
|
252
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
252
253
|
timer = setInterval(() => {
|
|
253
254
|
refresh().catch(() => {});
|
|
254
255
|
}, options.intervalMs);
|
|
@@ -258,7 +259,6 @@ var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-p
|
|
|
258
259
|
getServerSnapshot: () => snapshot,
|
|
259
260
|
getSnapshot: () => snapshot,
|
|
260
261
|
refresh,
|
|
261
|
-
runProof,
|
|
262
262
|
subscribe: (listener) => {
|
|
263
263
|
listeners.add(listener);
|
|
264
264
|
return () => {
|
|
@@ -268,11 +268,9 @@ var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-p
|
|
|
268
268
|
};
|
|
269
269
|
};
|
|
270
270
|
|
|
271
|
-
// src/svelte/createVoiceCampaignDialerProof.ts
|
|
272
|
-
var createVoiceCampaignDialerProof = (path = "/api/voice/campaigns/dialer-proof", options = {}) => createVoiceCampaignDialerProofStore(path, options);
|
|
273
271
|
// src/client/opsStatusWidget.ts
|
|
274
272
|
var DEFAULT_TITLE = "Voice Ops Status";
|
|
275
|
-
var DEFAULT_DESCRIPTION = "Certified workflow, provider, and handoff readiness from
|
|
273
|
+
var DEFAULT_DESCRIPTION = "Certified workflow, provider, and handoff readiness from your AbsoluteJS voice app.";
|
|
276
274
|
var SURFACE_LABELS = {
|
|
277
275
|
handoffs: "Handoffs",
|
|
278
276
|
providers: "Providers",
|
|
@@ -357,8 +355,8 @@ var renderVoiceOpsStatusHTML = (snapshot, options = {}) => {
|
|
|
357
355
|
</section>`;
|
|
358
356
|
};
|
|
359
357
|
var getVoiceOpsStatusCSS = () => `.absolute-voice-ops-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-ops-status--fail,.absolute-voice-ops-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-ops-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-ops-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-ops-status__label{font-size:28px;line-height:1}.absolute-voice-ops-status__description{color:#514733;margin:12px 0 0}.absolute-voice-ops-status__summary,.absolute-voice-ops-status__links{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}.absolute-voice-ops-status__summary span,.absolute-voice-ops-status__links a{border:1px solid #e6ddca;border-radius:999px;color:inherit;padding:6px 10px;text-decoration:none}.absolute-voice-ops-status__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-ops-status__surface{align-items:center;background:#fff;border:1px solid #eee4d2;border-radius:14px;display:flex;gap:12px;justify-content:space-between;padding:10px 12px}.absolute-voice-ops-status__surface--fail{border-color:#f2a7a7}.absolute-voice-ops-status__surface span{color:#655944}.absolute-voice-ops-status__error{color:#9f1239;font-weight:700}`;
|
|
360
|
-
var mountVoiceOpsStatus = (element, path = "/
|
|
361
|
-
const store =
|
|
358
|
+
var mountVoiceOpsStatus = (element, path = "/api/voice/ops-status", options = {}) => {
|
|
359
|
+
const store = createVoiceOpsStatusStore(path, options);
|
|
362
360
|
const render = () => {
|
|
363
361
|
element.innerHTML = renderVoiceOpsStatusHTML(store.getSnapshot(), options);
|
|
364
362
|
};
|
|
@@ -381,7 +379,7 @@ var defineVoiceOpsStatusElement = (tagName = "absolute-voice-ops-status") => {
|
|
|
381
379
|
mounted;
|
|
382
380
|
connectedCallback() {
|
|
383
381
|
const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
|
|
384
|
-
this.mounted = mountVoiceOpsStatus(this, this.getAttribute("path") ?? "/
|
|
382
|
+
this.mounted = mountVoiceOpsStatus(this, this.getAttribute("path") ?? "/api/voice/ops-status", {
|
|
385
383
|
description: this.getAttribute("description") ?? undefined,
|
|
386
384
|
includeLinks: this.getAttribute("include-links") !== "false",
|
|
387
385
|
intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
|
|
@@ -396,8 +394,8 @@ var defineVoiceOpsStatusElement = (tagName = "absolute-voice-ops-status") => {
|
|
|
396
394
|
};
|
|
397
395
|
|
|
398
396
|
// src/svelte/createVoiceOpsStatus.ts
|
|
399
|
-
var createVoiceOpsStatus = (path = "/
|
|
400
|
-
const store =
|
|
397
|
+
var createVoiceOpsStatus = (path = "/api/voice/ops-status", options = {}) => {
|
|
398
|
+
const store = createVoiceOpsStatusStore(path, options);
|
|
401
399
|
return {
|
|
402
400
|
close: store.close,
|
|
403
401
|
getHTML: () => renderVoiceOpsStatusHTML(store.getSnapshot(), options),
|
|
@@ -3017,6 +3015,5 @@ export {
|
|
|
3017
3015
|
createVoiceProviderCapabilities,
|
|
3018
3016
|
createVoiceOpsStatus,
|
|
3019
3017
|
createVoiceController,
|
|
3020
|
-
createVoiceCampaignDialerProof
|
|
3021
|
-
createVoiceAppKitStatus
|
|
3018
|
+
createVoiceCampaignDialerProof
|
|
3022
3019
|
};
|
|
@@ -2,7 +2,7 @@ import { Elysia } from 'elysia';
|
|
|
2
2
|
import type { VoiceTelephonySetupStatus, VoiceTelephonySmokeCheck, VoiceTelephonySmokeReport } from './contract';
|
|
3
3
|
import { type VoiceTelephonyOutcomePolicy, type VoiceTelephonyWebhookRoutesOptions } from '../telephonyOutcome';
|
|
4
4
|
import { type VoiceCallReviewArtifact, type VoiceCallReviewConfig } from '../testing/review';
|
|
5
|
-
import type { AudioFormat, VoiceLogger, VoicePluginConfig, VoiceSessionRecord, VoiceServerMessage } from '../types';
|
|
5
|
+
import type { AudioFormat, STTAdapter, VoiceLogger, VoicePluginConfig, VoiceSessionRecord, VoiceServerMessage } from '../types';
|
|
6
6
|
type TwilioMediaPayload = {
|
|
7
7
|
chunk?: string;
|
|
8
8
|
payload: string;
|
|
@@ -78,7 +78,7 @@ export type TwilioMediaStreamSocket = {
|
|
|
78
78
|
close: (code?: number, reason?: string) => void | Promise<void>;
|
|
79
79
|
send: (data: string) => void | Promise<void>;
|
|
80
80
|
};
|
|
81
|
-
export type TwilioMediaStreamBridgeOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = Omit<VoicePluginConfig<TContext, TSession, TResult>, 'htmx' | 'path'> & {
|
|
81
|
+
export type TwilioMediaStreamBridgeOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = Omit<VoicePluginConfig<TContext, TSession, TResult>, 'htmx' | 'path' | 'stt'> & {
|
|
82
82
|
clearOnInboundMedia?: boolean;
|
|
83
83
|
context: TContext;
|
|
84
84
|
logger?: VoiceLogger;
|
|
@@ -97,6 +97,7 @@ export type TwilioMediaStreamBridgeOptions<TContext = unknown, TSession extends
|
|
|
97
97
|
};
|
|
98
98
|
scenarioId?: string;
|
|
99
99
|
sessionId?: string;
|
|
100
|
+
stt: STTAdapter;
|
|
100
101
|
};
|
|
101
102
|
export type TwilioMediaStreamBridge = {
|
|
102
103
|
close: (reason?: string) => Promise<void>;
|
package/dist/testing/index.js
CHANGED
|
@@ -5033,6 +5033,12 @@ var DEFAULT_FORMAT = {
|
|
|
5033
5033
|
encoding: "pcm_s16le",
|
|
5034
5034
|
sampleRateHz: 16000
|
|
5035
5035
|
};
|
|
5036
|
+
var DEFAULT_REALTIME_FORMAT = {
|
|
5037
|
+
channels: 1,
|
|
5038
|
+
container: "raw",
|
|
5039
|
+
encoding: "pcm_s16le",
|
|
5040
|
+
sampleRateHz: 24000
|
|
5041
|
+
};
|
|
5036
5042
|
var toError = (value) => value instanceof Error ? value : new Error(String(value));
|
|
5037
5043
|
var createEmptyCurrentTurn = () => ({
|
|
5038
5044
|
finalText: "",
|
|
@@ -5413,6 +5419,23 @@ var createVoiceSession = (options) => {
|
|
|
5413
5419
|
});
|
|
5414
5420
|
}
|
|
5415
5421
|
};
|
|
5422
|
+
const sendAssistantAudio = async (chunk, input) => {
|
|
5423
|
+
const normalizedChunk = chunk instanceof Uint8Array ? new Uint8Array(chunk) : chunk instanceof ArrayBuffer ? new Uint8Array(chunk.slice(0)) : new Uint8Array(chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength));
|
|
5424
|
+
await send({
|
|
5425
|
+
chunkBase64: encodeBase64(normalizedChunk),
|
|
5426
|
+
format: input.format,
|
|
5427
|
+
receivedAt: input.receivedAt,
|
|
5428
|
+
turnId: activeTTSTurnId,
|
|
5429
|
+
type: "audio"
|
|
5430
|
+
});
|
|
5431
|
+
if (activeTTSTurnId) {
|
|
5432
|
+
await appendTurnLatencyStage({
|
|
5433
|
+
at: input.receivedAt,
|
|
5434
|
+
stage: "assistant_audio_received",
|
|
5435
|
+
turnId: activeTTSTurnId
|
|
5436
|
+
});
|
|
5437
|
+
}
|
|
5438
|
+
};
|
|
5416
5439
|
const scheduleTurnCommit = (delayMs, reason, reset = true) => {
|
|
5417
5440
|
if (!reset && silenceTimer) {
|
|
5418
5441
|
return;
|
|
@@ -6114,8 +6137,12 @@ var createVoiceSession = (options) => {
|
|
|
6114
6137
|
if (sttSession) {
|
|
6115
6138
|
return sttSession;
|
|
6116
6139
|
}
|
|
6117
|
-
const
|
|
6118
|
-
|
|
6140
|
+
const inputAdapter = options.realtime ?? options.stt;
|
|
6141
|
+
if (!inputAdapter) {
|
|
6142
|
+
throw new Error("Voice session requires either an stt or realtime adapter.");
|
|
6143
|
+
}
|
|
6144
|
+
const openedSession = await inputAdapter.open({
|
|
6145
|
+
format: options.realtime ? options.realtimeInputFormat ?? DEFAULT_REALTIME_FORMAT : DEFAULT_FORMAT,
|
|
6119
6146
|
languageStrategy: options.languageStrategy,
|
|
6120
6147
|
lexicon,
|
|
6121
6148
|
phraseHints,
|
|
@@ -6150,6 +6177,16 @@ var createVoiceSession = (options) => {
|
|
|
6150
6177
|
openedSession.on("close", (event) => {
|
|
6151
6178
|
runAdapterEvent("adapter.close", () => handleClose(event));
|
|
6152
6179
|
});
|
|
6180
|
+
if (options.realtime) {
|
|
6181
|
+
openedSession.on("audio", ({ chunk, format, receivedAt }) => {
|
|
6182
|
+
runAdapterEvent("adapter.audio", async () => {
|
|
6183
|
+
await sendAssistantAudio(chunk, {
|
|
6184
|
+
format,
|
|
6185
|
+
receivedAt
|
|
6186
|
+
});
|
|
6187
|
+
});
|
|
6188
|
+
});
|
|
6189
|
+
}
|
|
6153
6190
|
return openedSession;
|
|
6154
6191
|
};
|
|
6155
6192
|
const ensureTTSSession = async () => {
|
|
@@ -6174,21 +6211,10 @@ var createVoiceSession = (options) => {
|
|
|
6174
6211
|
if (ttsSession !== openedSession) {
|
|
6175
6212
|
return;
|
|
6176
6213
|
}
|
|
6177
|
-
|
|
6178
|
-
await send({
|
|
6179
|
-
chunkBase64: encodeBase64(normalizedChunk),
|
|
6214
|
+
await sendAssistantAudio(chunk, {
|
|
6180
6215
|
format,
|
|
6181
|
-
receivedAt
|
|
6182
|
-
turnId: activeTTSTurnId,
|
|
6183
|
-
type: "audio"
|
|
6216
|
+
receivedAt
|
|
6184
6217
|
});
|
|
6185
|
-
if (activeTTSTurnId) {
|
|
6186
|
-
await appendTurnLatencyStage({
|
|
6187
|
-
at: receivedAt,
|
|
6188
|
-
stage: "assistant_audio_received",
|
|
6189
|
-
turnId: activeTTSTurnId
|
|
6190
|
-
});
|
|
6191
|
-
}
|
|
6192
6218
|
});
|
|
6193
6219
|
});
|
|
6194
6220
|
openedSession.on("error", (event) => {
|
|
@@ -6267,7 +6293,8 @@ var createVoiceSession = (options) => {
|
|
|
6267
6293
|
await appendTrace({
|
|
6268
6294
|
payload: {
|
|
6269
6295
|
text: output.assistantText,
|
|
6270
|
-
ttsConfigured: Boolean(options.tts)
|
|
6296
|
+
ttsConfigured: Boolean(options.tts),
|
|
6297
|
+
realtimeConfigured: Boolean(options.realtime)
|
|
6271
6298
|
},
|
|
6272
6299
|
session,
|
|
6273
6300
|
turnId: turn.id,
|
|
@@ -6299,9 +6326,35 @@ var createVoiceSession = (options) => {
|
|
|
6299
6326
|
turnId: turn.id,
|
|
6300
6327
|
type: "turn.assistant"
|
|
6301
6328
|
});
|
|
6329
|
+
} else if (options.realtime) {
|
|
6330
|
+
const activeRealtimeSession = await ensureAdapter();
|
|
6331
|
+
const realtimeStartedAt = Date.now();
|
|
6332
|
+
activeTTSTurnId = turn.id;
|
|
6333
|
+
await appendTurnLatencyStage({
|
|
6334
|
+
at: realtimeStartedAt,
|
|
6335
|
+
session,
|
|
6336
|
+
stage: "tts_send_started",
|
|
6337
|
+
turnId: turn.id
|
|
6338
|
+
});
|
|
6339
|
+
await activeRealtimeSession.send(output.assistantText);
|
|
6340
|
+
await appendTurnLatencyStage({
|
|
6341
|
+
session,
|
|
6342
|
+
stage: "tts_send_completed",
|
|
6343
|
+
turnId: turn.id
|
|
6344
|
+
});
|
|
6345
|
+
await appendTrace({
|
|
6346
|
+
payload: {
|
|
6347
|
+
elapsedMs: Date.now() - realtimeStartedAt,
|
|
6348
|
+
mode: "realtime",
|
|
6349
|
+
status: "sent"
|
|
6350
|
+
},
|
|
6351
|
+
session,
|
|
6352
|
+
turnId: turn.id,
|
|
6353
|
+
type: "turn.assistant"
|
|
6354
|
+
});
|
|
6302
6355
|
}
|
|
6303
6356
|
} catch (error) {
|
|
6304
|
-
logger.warn("voice
|
|
6357
|
+
logger.warn("voice assistant audio send failed", {
|
|
6305
6358
|
error: toError(error).message,
|
|
6306
6359
|
sessionId: options.id,
|
|
6307
6360
|
turnId: turn.id
|
|
@@ -6309,7 +6362,7 @@ var createVoiceSession = (options) => {
|
|
|
6309
6362
|
await appendTrace({
|
|
6310
6363
|
payload: {
|
|
6311
6364
|
error: toError(error).message,
|
|
6312
|
-
status: "tts-send-failed"
|
|
6365
|
+
status: options.realtime ? "realtime-send-failed" : "tts-send-failed"
|
|
6313
6366
|
},
|
|
6314
6367
|
session,
|
|
6315
6368
|
turnId: turn.id,
|
|
@@ -6514,7 +6567,7 @@ var createVoiceSession = (options) => {
|
|
|
6514
6567
|
turn,
|
|
6515
6568
|
type: "turn"
|
|
6516
6569
|
});
|
|
6517
|
-
if (options.sttLifecycle === "turn-scoped") {
|
|
6570
|
+
if (options.stt && options.sttLifecycle === "turn-scoped") {
|
|
6518
6571
|
await closeAdapter("turn-commit");
|
|
6519
6572
|
}
|
|
6520
6573
|
await completeTurn(updatedSession, turn);
|
|
@@ -9600,7 +9653,7 @@ var runVoiceTelephonyBenchmark = async (scenarios = getDefaultVoiceTelephonyBenc
|
|
|
9600
9653
|
};
|
|
9601
9654
|
};
|
|
9602
9655
|
// src/testing/tts.ts
|
|
9603
|
-
var
|
|
9656
|
+
var DEFAULT_REALTIME_FORMAT2 = {
|
|
9604
9657
|
channels: 1,
|
|
9605
9658
|
container: "raw",
|
|
9606
9659
|
encoding: "pcm_s16le",
|
|
@@ -9659,7 +9712,7 @@ var runTTSAdapterFixture = async (adapter, fixture, options = {}) => {
|
|
|
9659
9712
|
let audioDurationMs = 0;
|
|
9660
9713
|
let audioChunkCount = 0;
|
|
9661
9714
|
const session = adapter.kind === "realtime" ? await adapter.open({
|
|
9662
|
-
format: options.realtimeFormat ??
|
|
9715
|
+
format: options.realtimeFormat ?? DEFAULT_REALTIME_FORMAT2,
|
|
9663
9716
|
sessionId: `tts-benchmark:${fixture.id}`,
|
|
9664
9717
|
...openOptions ?? {}
|
|
9665
9718
|
}) : await adapter.open({
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import { type VoiceTraceSinkDeliveryQueueSummary, type VoiceTraceSinkDeliveryWorkerResult } from './queue';
|
|
3
|
+
import type { VoiceTraceSinkDeliveryQueueStatus, VoiceTraceSinkDeliveryRecord, VoiceTraceSinkDeliveryStore } from './trace';
|
|
4
|
+
export type VoiceTraceDeliveryReport = {
|
|
5
|
+
checkedAt: number;
|
|
6
|
+
deliveries: VoiceTraceSinkDeliveryRecord[];
|
|
7
|
+
filter: VoiceTraceDeliveryFilter;
|
|
8
|
+
summary: VoiceTraceSinkDeliveryQueueSummary;
|
|
9
|
+
};
|
|
10
|
+
export type VoiceTraceDeliveryDrainWorker = {
|
|
11
|
+
drain: () => Promise<VoiceTraceSinkDeliveryWorkerResult> | VoiceTraceSinkDeliveryWorkerResult;
|
|
12
|
+
};
|
|
13
|
+
export type VoiceTraceDeliveryDrainReport = VoiceTraceSinkDeliveryWorkerResult & {
|
|
14
|
+
drainedAt: number;
|
|
15
|
+
};
|
|
16
|
+
export type VoiceTraceDeliveryFilter = {
|
|
17
|
+
limit?: number;
|
|
18
|
+
q?: string;
|
|
19
|
+
status?: VoiceTraceSinkDeliveryQueueStatus | 'all';
|
|
20
|
+
};
|
|
21
|
+
export type VoiceTraceDeliveryRoutesOptions = {
|
|
22
|
+
deadLetters?: VoiceTraceSinkDeliveryStore;
|
|
23
|
+
filter?: VoiceTraceDeliveryFilter;
|
|
24
|
+
headers?: HeadersInit;
|
|
25
|
+
htmlPath?: false | string;
|
|
26
|
+
limit?: number;
|
|
27
|
+
name?: string;
|
|
28
|
+
path?: string;
|
|
29
|
+
render?: (report: VoiceTraceDeliveryReport) => string | Promise<string>;
|
|
30
|
+
store: VoiceTraceSinkDeliveryStore;
|
|
31
|
+
title?: string;
|
|
32
|
+
worker?: VoiceTraceDeliveryDrainWorker;
|
|
33
|
+
workerPath?: false | string;
|
|
34
|
+
};
|
|
35
|
+
export declare const resolveVoiceTraceDeliveryFilter: (query?: Record<string, unknown>, base?: VoiceTraceDeliveryFilter) => VoiceTraceDeliveryFilter;
|
|
36
|
+
export declare const buildVoiceTraceDeliveryReport: (options: VoiceTraceDeliveryRoutesOptions, filter?: VoiceTraceDeliveryFilter) => Promise<VoiceTraceDeliveryReport>;
|
|
37
|
+
export declare const renderVoiceTraceDeliveryHTML: (report: VoiceTraceDeliveryReport, options?: {
|
|
38
|
+
title?: string;
|
|
39
|
+
workerPath?: false | string;
|
|
40
|
+
}) => string;
|
|
41
|
+
export declare const createVoiceTraceDeliveryJSONHandler: (options: VoiceTraceDeliveryRoutesOptions) => ({ query }: {
|
|
42
|
+
query?: Record<string, string | undefined>;
|
|
43
|
+
}) => Promise<VoiceTraceDeliveryReport>;
|
|
44
|
+
export declare const createVoiceTraceDeliveryHTMLHandler: (options: VoiceTraceDeliveryRoutesOptions) => ({ query }: {
|
|
45
|
+
query?: Record<string, string | undefined>;
|
|
46
|
+
}) => Promise<Response>;
|
|
47
|
+
export declare const createVoiceTraceDeliveryRoutes: (options: VoiceTraceDeliveryRoutesOptions) => Elysia<"", {
|
|
48
|
+
decorator: {};
|
|
49
|
+
store: {};
|
|
50
|
+
derive: {};
|
|
51
|
+
resolve: {};
|
|
52
|
+
}, {
|
|
53
|
+
typebox: {};
|
|
54
|
+
error: {};
|
|
55
|
+
}, {
|
|
56
|
+
schema: {};
|
|
57
|
+
standaloneSchema: {};
|
|
58
|
+
macro: {};
|
|
59
|
+
macroFn: {};
|
|
60
|
+
parser: {};
|
|
61
|
+
response: {};
|
|
62
|
+
}, {
|
|
63
|
+
[x: string]: {
|
|
64
|
+
get: {
|
|
65
|
+
body: unknown;
|
|
66
|
+
params: {};
|
|
67
|
+
query: unknown;
|
|
68
|
+
headers: unknown;
|
|
69
|
+
response: {
|
|
70
|
+
200: VoiceTraceDeliveryReport;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
}, {
|
|
75
|
+
derive: {};
|
|
76
|
+
resolve: {};
|
|
77
|
+
schema: {};
|
|
78
|
+
standaloneSchema: {};
|
|
79
|
+
response: {};
|
|
80
|
+
}, {
|
|
81
|
+
derive: {};
|
|
82
|
+
resolve: {};
|
|
83
|
+
schema: {};
|
|
84
|
+
standaloneSchema: {};
|
|
85
|
+
response: {};
|
|
86
|
+
}>;
|
package/dist/types.d.ts
CHANGED
|
@@ -616,9 +616,11 @@ export type VoicePluginConfig<TContext = unknown, TSession extends VoiceSessionR
|
|
|
616
616
|
lexicon?: VoiceLexiconEntry[] | VoiceLexiconResolver<TContext>;
|
|
617
617
|
phraseHints?: VoicePhraseHint[] | VoicePhraseHintResolver<TContext>;
|
|
618
618
|
preset?: VoiceRuntimePreset;
|
|
619
|
-
stt
|
|
619
|
+
stt?: STTAdapter;
|
|
620
620
|
sttFallback?: VoiceSTTFallbackConfig;
|
|
621
621
|
sttLifecycle?: VoiceSTTLifecycle;
|
|
622
|
+
realtime?: RealtimeAdapter;
|
|
623
|
+
realtimeInputFormat?: AudioFormat;
|
|
622
624
|
tts?: TTSAdapter;
|
|
623
625
|
session: VoiceSessionStore<NoInfer<TSession>>;
|
|
624
626
|
reconnect?: VoiceReconnectConfig;
|
|
@@ -635,7 +637,9 @@ export type CreateVoiceSessionOptions<TContext = unknown, TSession extends Voice
|
|
|
635
637
|
id: string;
|
|
636
638
|
context: TContext;
|
|
637
639
|
socket: VoiceSocket;
|
|
638
|
-
stt
|
|
640
|
+
stt?: STTAdapter;
|
|
641
|
+
realtime?: RealtimeAdapter;
|
|
642
|
+
realtimeInputFormat?: AudioFormat;
|
|
639
643
|
tts?: TTSAdapter;
|
|
640
644
|
languageStrategy?: VoiceLanguageStrategy;
|
|
641
645
|
lexicon?: VoiceLexiconEntry[];
|
package/dist/vue/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { VoiceProviderStatus } from './VoiceProviderStatus';
|
|
|
5
5
|
export { VoiceRoutingStatus } from './VoiceRoutingStatus';
|
|
6
6
|
export { VoiceTurnLatency } from './VoiceTurnLatency';
|
|
7
7
|
export { VoiceTurnQuality } from './VoiceTurnQuality';
|
|
8
|
-
export {
|
|
8
|
+
export { useVoiceOpsStatus } from './useVoiceOpsStatus';
|
|
9
9
|
export { useVoiceCampaignDialerProof } from './useVoiceCampaignDialerProof';
|
|
10
10
|
export { useVoiceStream } from './useVoiceStream';
|
|
11
11
|
export { useVoiceController } from './useVoiceController';
|