@absolutejs/voice 0.0.22-beta.497 → 0.0.22-beta.499
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/assistant.d.ts +1 -2
- package/dist/callQuota.d.ts +54 -0
- package/dist/client/costDashboard.d.ts +27 -0
- package/dist/client/liveCallViewer.d.ts +42 -0
- package/dist/client/replayTimeline.d.ts +26 -0
- package/dist/defineVoiceAssistant.d.ts +68 -0
- package/dist/index.d.ts +18 -2
- package/dist/index.js +640 -37
- package/dist/midCallSummary.d.ts +27 -0
- package/dist/recordingRedaction.d.ts +18 -0
- package/dist/recordingStore.d.ts +39 -0
- package/dist/retention.d.ts +37 -0
- package/dist/routeAuth.d.ts +58 -0
- package/dist/testing/index.js +33 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3413,6 +3413,39 @@ var encodePcmAsWav = (pcm, format) => {
|
|
|
3413
3413
|
output.set(pcm, 44);
|
|
3414
3414
|
return output;
|
|
3415
3415
|
};
|
|
3416
|
+
var interleaveStereoPcm = (input) => {
|
|
3417
|
+
const leftSamples = new Int16Array(input.left.buffer, input.left.byteOffset, Math.floor(input.left.byteLength / 2));
|
|
3418
|
+
const rightSamples = new Int16Array(input.right.buffer, input.right.byteOffset, Math.floor(input.right.byteLength / 2));
|
|
3419
|
+
const frameCount = Math.max(leftSamples.length, rightSamples.length);
|
|
3420
|
+
const output = new Int16Array(frameCount * 2);
|
|
3421
|
+
for (let frame = 0;frame < frameCount; frame += 1) {
|
|
3422
|
+
output[frame * 2] = leftSamples[frame] ?? 0;
|
|
3423
|
+
output[frame * 2 + 1] = rightSamples[frame] ?? 0;
|
|
3424
|
+
}
|
|
3425
|
+
return new Uint8Array(output.buffer);
|
|
3426
|
+
};
|
|
3427
|
+
var encodeStereoWav = ({
|
|
3428
|
+
format,
|
|
3429
|
+
left,
|
|
3430
|
+
right
|
|
3431
|
+
}) => {
|
|
3432
|
+
if (format.container !== "raw" || format.encoding !== "pcm_s16le") {
|
|
3433
|
+
throw new Error("encodeStereoWav requires raw pcm_s16le format on each channel");
|
|
3434
|
+
}
|
|
3435
|
+
if (format.channels !== 1) {
|
|
3436
|
+
throw new Error("encodeStereoWav expects mono input channels");
|
|
3437
|
+
}
|
|
3438
|
+
const interleaved = interleaveStereoPcm({ left, right });
|
|
3439
|
+
return encodePcmAsWav(interleaved, { ...format, channels: 2 });
|
|
3440
|
+
};
|
|
3441
|
+
var createVoiceWavRecordingEncoder = () => ({
|
|
3442
|
+
encode: ({ format, pcm }) => ({
|
|
3443
|
+
bytes: encodePcmAsWav(pcm, format),
|
|
3444
|
+
contentType: "audio/wav",
|
|
3445
|
+
extension: "wav"
|
|
3446
|
+
}),
|
|
3447
|
+
kind: "wav"
|
|
3448
|
+
});
|
|
3416
3449
|
var computePcmDurationMs = (pcmByteLength, format) => {
|
|
3417
3450
|
if (format.container !== "raw" || format.encoding !== "pcm_s16le") {
|
|
3418
3451
|
return 0;
|
|
@@ -35232,6 +35265,44 @@ var createVoiceTranscriptRedactor = (options = {}) => {
|
|
|
35232
35265
|
};
|
|
35233
35266
|
};
|
|
35234
35267
|
var redactVoiceTranscript = (transcript, patterns = DEFAULT_VOICE_REDACTION_PATTERNS) => createVoiceTranscriptRedactor({ patterns })(transcript);
|
|
35268
|
+
// src/recordingRedaction.ts
|
|
35269
|
+
var matchesAnyPattern = (text, patterns) => {
|
|
35270
|
+
for (const pattern of patterns) {
|
|
35271
|
+
pattern.regex.lastIndex = 0;
|
|
35272
|
+
if (pattern.regex.test(text)) {
|
|
35273
|
+
pattern.regex.lastIndex = 0;
|
|
35274
|
+
return pattern;
|
|
35275
|
+
}
|
|
35276
|
+
}
|
|
35277
|
+
return;
|
|
35278
|
+
};
|
|
35279
|
+
var deriveVoiceRecordingRedactionRanges = (input) => {
|
|
35280
|
+
const patterns = input.patterns ?? DEFAULT_VOICE_REDACTION_PATTERNS;
|
|
35281
|
+
const padding = Math.max(0, input.paddingMs ?? 100);
|
|
35282
|
+
const baseEpoch = input.recordingStartedAtEpochMs;
|
|
35283
|
+
const out = [];
|
|
35284
|
+
for (const transcript of input.transcripts) {
|
|
35285
|
+
if (!transcript.isFinal)
|
|
35286
|
+
continue;
|
|
35287
|
+
if (typeof transcript.startedAtMs !== "number")
|
|
35288
|
+
continue;
|
|
35289
|
+
if (typeof transcript.endedAtMs !== "number")
|
|
35290
|
+
continue;
|
|
35291
|
+
const matched = matchesAnyPattern(transcript.text, patterns);
|
|
35292
|
+
if (!matched)
|
|
35293
|
+
continue;
|
|
35294
|
+
const absStart = transcript.startedAtMs;
|
|
35295
|
+
const absEnd = transcript.endedAtMs;
|
|
35296
|
+
const start = typeof baseEpoch === "number" && absStart >= baseEpoch ? absStart - baseEpoch : absStart;
|
|
35297
|
+
const end = typeof baseEpoch === "number" && absEnd >= baseEpoch ? absEnd - baseEpoch : absEnd;
|
|
35298
|
+
out.push({
|
|
35299
|
+
endMs: end + padding,
|
|
35300
|
+
label: matched.label,
|
|
35301
|
+
startMs: Math.max(0, start - padding)
|
|
35302
|
+
});
|
|
35303
|
+
}
|
|
35304
|
+
return out;
|
|
35305
|
+
};
|
|
35235
35306
|
// src/costAccounting.ts
|
|
35236
35307
|
var DEFAULT_VOICE_PRICE_BOOK = {
|
|
35237
35308
|
"anthropic:claude-opus-4-5": {
|
|
@@ -36481,6 +36552,524 @@ var createVoiceApiRequestTool = (options) => {
|
|
|
36481
36552
|
resultToMessage: options.formatResult ?? ((result) => result.ok ? `API request ${options.name} succeeded (${String(result.status)}).` : `API request ${options.name} failed with status ${String(result.status)}.`)
|
|
36482
36553
|
});
|
|
36483
36554
|
};
|
|
36555
|
+
// src/defineVoiceAssistant.ts
|
|
36556
|
+
var DEFAULT_SPEECH_THRESHOLD2 = 0.015;
|
|
36557
|
+
var DEFAULT_SILENCE_MS2 = 700;
|
|
36558
|
+
var DEFAULT_TRANSCRIPT_STABILITY_MS2 = 200;
|
|
36559
|
+
var resolveTurnDetection = (input) => ({
|
|
36560
|
+
profile: input?.profile ?? "balanced",
|
|
36561
|
+
qualityProfile: input?.qualityProfile ?? "general",
|
|
36562
|
+
silenceMs: input?.silenceMs ?? DEFAULT_SILENCE_MS2,
|
|
36563
|
+
speechThreshold: input?.speechThreshold ?? DEFAULT_SPEECH_THRESHOLD2,
|
|
36564
|
+
transcriptStabilityMs: input?.transcriptStabilityMs ?? DEFAULT_TRANSCRIPT_STABILITY_MS2
|
|
36565
|
+
});
|
|
36566
|
+
var resolveReconnect = (input) => ({
|
|
36567
|
+
maxAttempts: input?.maxAttempts ?? 3,
|
|
36568
|
+
strategy: input?.strategy ?? "resume-last-turn",
|
|
36569
|
+
timeout: input?.timeout ?? 30000
|
|
36570
|
+
});
|
|
36571
|
+
var buildAssistantOptions = (def) => ({
|
|
36572
|
+
...def.agent,
|
|
36573
|
+
guardrails: def.guardrails,
|
|
36574
|
+
id: def.id,
|
|
36575
|
+
memory: def.memory,
|
|
36576
|
+
memoryLifecycle: def.memoryLifecycle,
|
|
36577
|
+
ops: def.ops
|
|
36578
|
+
});
|
|
36579
|
+
var defineVoiceAssistant = (definition) => {
|
|
36580
|
+
const assistantOptions = buildAssistantOptions(definition);
|
|
36581
|
+
const assistant = createVoiceAssistant(assistantOptions);
|
|
36582
|
+
return {
|
|
36583
|
+
assistant,
|
|
36584
|
+
definition,
|
|
36585
|
+
id: definition.id,
|
|
36586
|
+
toSessionOptions: (input) => {
|
|
36587
|
+
const route = assistant.route(definition.route ?? {});
|
|
36588
|
+
const observability = definition.observability ?? {};
|
|
36589
|
+
return {
|
|
36590
|
+
amd: definition.amd,
|
|
36591
|
+
assistantMode: definition.assistantMode,
|
|
36592
|
+
audioConditioning: definition.audioConditioning,
|
|
36593
|
+
callSilenceTimeoutMs: definition.callSilenceTimeoutMs,
|
|
36594
|
+
context: input.context,
|
|
36595
|
+
costAccountant: observability.costAccountant,
|
|
36596
|
+
costTelephony: observability.costTelephony,
|
|
36597
|
+
id: input.id,
|
|
36598
|
+
languageStrategy: definition.languageStrategy,
|
|
36599
|
+
lexicon: definition.lexicon,
|
|
36600
|
+
modalities: definition.modalities,
|
|
36601
|
+
phraseHints: definition.phraseHints,
|
|
36602
|
+
prosody: definition.voice.prosody,
|
|
36603
|
+
realtime: definition.voice.realtime,
|
|
36604
|
+
realtimeInputFormat: definition.voice.realtimeInputFormat,
|
|
36605
|
+
reconnect: resolveReconnect(input.reconnect),
|
|
36606
|
+
recording: observability.recording,
|
|
36607
|
+
redact: definition.redact,
|
|
36608
|
+
route,
|
|
36609
|
+
scenarioId: input.scenarioId,
|
|
36610
|
+
semanticTurnDetector: definition.semanticTurnDetector,
|
|
36611
|
+
sessionMetadata: { ...definition.metadata, ...input.sessionMetadata },
|
|
36612
|
+
socket: input.socket,
|
|
36613
|
+
store: input.store,
|
|
36614
|
+
stt: definition.voice.stt,
|
|
36615
|
+
sttFallback: definition.voice.sttFallback,
|
|
36616
|
+
sttLifecycle: input.sttLifecycle ?? "continuous",
|
|
36617
|
+
trace: observability.trace,
|
|
36618
|
+
tts: definition.voice.tts,
|
|
36619
|
+
turnDetection: resolveTurnDetection(definition.turnDetection)
|
|
36620
|
+
};
|
|
36621
|
+
}
|
|
36622
|
+
};
|
|
36623
|
+
};
|
|
36624
|
+
// src/callQuota.ts
|
|
36625
|
+
var monthBucketKey = (epochMs) => {
|
|
36626
|
+
const date = new Date(epochMs);
|
|
36627
|
+
return `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, "0")}`;
|
|
36628
|
+
};
|
|
36629
|
+
var createInMemoryVoiceCallQuota = (options) => {
|
|
36630
|
+
const tiers = new Map(options.tiers.map((tier) => [tier.customerId, tier]));
|
|
36631
|
+
const activeCalls = new Map;
|
|
36632
|
+
const monthlyUsage = new Map;
|
|
36633
|
+
const usageFor = (customerId) => {
|
|
36634
|
+
const key = monthBucketKey(Date.now());
|
|
36635
|
+
let bucket = monthlyUsage.get(customerId);
|
|
36636
|
+
if (!bucket) {
|
|
36637
|
+
bucket = new Map;
|
|
36638
|
+
monthlyUsage.set(customerId, bucket);
|
|
36639
|
+
}
|
|
36640
|
+
return { bucket, key };
|
|
36641
|
+
};
|
|
36642
|
+
return {
|
|
36643
|
+
describe: (customerId) => {
|
|
36644
|
+
const tier = tiers.get(customerId);
|
|
36645
|
+
if (!tier)
|
|
36646
|
+
return;
|
|
36647
|
+
const active = activeCalls.get(customerId)?.size ?? 0;
|
|
36648
|
+
const { bucket, key } = usageFor(customerId);
|
|
36649
|
+
return {
|
|
36650
|
+
activeCalls: active,
|
|
36651
|
+
burstAllowance: tier.burstAllowance ?? 0,
|
|
36652
|
+
monthlyMinutesUsed: bucket.get(key) ?? 0,
|
|
36653
|
+
reservedConcurrent: tier.reservedConcurrent,
|
|
36654
|
+
tier
|
|
36655
|
+
};
|
|
36656
|
+
},
|
|
36657
|
+
recordMinutes: ({ customerId, minutes }) => {
|
|
36658
|
+
const { bucket, key } = usageFor(customerId);
|
|
36659
|
+
bucket.set(key, (bucket.get(key) ?? 0) + Math.max(0, minutes));
|
|
36660
|
+
},
|
|
36661
|
+
reserve: ({ callId, customerId }) => {
|
|
36662
|
+
const tier = tiers.get(customerId);
|
|
36663
|
+
if (!tier) {
|
|
36664
|
+
if (options.strict) {
|
|
36665
|
+
return {
|
|
36666
|
+
ok: false,
|
|
36667
|
+
rejection: { customerId, reason: "customer-not-found" }
|
|
36668
|
+
};
|
|
36669
|
+
}
|
|
36670
|
+
return {
|
|
36671
|
+
ok: true,
|
|
36672
|
+
reservation: {
|
|
36673
|
+
callId,
|
|
36674
|
+
customerId,
|
|
36675
|
+
release: () => {},
|
|
36676
|
+
reservedAt: Date.now()
|
|
36677
|
+
}
|
|
36678
|
+
};
|
|
36679
|
+
}
|
|
36680
|
+
const limit = tier.reservedConcurrent + (tier.burstAllowance ?? 0);
|
|
36681
|
+
const set = activeCalls.get(customerId) ?? new Set;
|
|
36682
|
+
if (set.size >= limit) {
|
|
36683
|
+
return {
|
|
36684
|
+
ok: false,
|
|
36685
|
+
rejection: {
|
|
36686
|
+
customerId,
|
|
36687
|
+
reason: "concurrency-exceeded",
|
|
36688
|
+
retryAfterMs: 30000
|
|
36689
|
+
}
|
|
36690
|
+
};
|
|
36691
|
+
}
|
|
36692
|
+
if (typeof tier.monthlyMinutes === "number") {
|
|
36693
|
+
const { bucket, key } = usageFor(customerId);
|
|
36694
|
+
if ((bucket.get(key) ?? 0) >= tier.monthlyMinutes) {
|
|
36695
|
+
return {
|
|
36696
|
+
ok: false,
|
|
36697
|
+
rejection: {
|
|
36698
|
+
customerId,
|
|
36699
|
+
reason: "monthly-minutes-exceeded"
|
|
36700
|
+
}
|
|
36701
|
+
};
|
|
36702
|
+
}
|
|
36703
|
+
}
|
|
36704
|
+
set.add(callId);
|
|
36705
|
+
activeCalls.set(customerId, set);
|
|
36706
|
+
return {
|
|
36707
|
+
ok: true,
|
|
36708
|
+
reservation: {
|
|
36709
|
+
callId,
|
|
36710
|
+
customerId,
|
|
36711
|
+
release: () => {
|
|
36712
|
+
set.delete(callId);
|
|
36713
|
+
if (set.size === 0)
|
|
36714
|
+
activeCalls.delete(customerId);
|
|
36715
|
+
},
|
|
36716
|
+
reservedAt: Date.now()
|
|
36717
|
+
}
|
|
36718
|
+
};
|
|
36719
|
+
}
|
|
36720
|
+
};
|
|
36721
|
+
};
|
|
36722
|
+
// src/routeAuth.ts
|
|
36723
|
+
import { Elysia as Elysia53 } from "elysia";
|
|
36724
|
+
var createVoiceBearerAuthVerifier = (input) => {
|
|
36725
|
+
const headerName = (input.headerName ?? "authorization").toLowerCase();
|
|
36726
|
+
const expected = `Bearer ${input.expectedToken}`;
|
|
36727
|
+
return ({ headers }) => {
|
|
36728
|
+
const value = headers.get(headerName);
|
|
36729
|
+
if (!value) {
|
|
36730
|
+
return { allow: false, reason: "missing-bearer", status: 401 };
|
|
36731
|
+
}
|
|
36732
|
+
if (value !== expected) {
|
|
36733
|
+
return { allow: false, reason: "bearer-mismatch", status: 401 };
|
|
36734
|
+
}
|
|
36735
|
+
return { allow: true };
|
|
36736
|
+
};
|
|
36737
|
+
};
|
|
36738
|
+
var createVoiceHMACAuthVerifier = (input) => {
|
|
36739
|
+
return async ({ body, headers }) => {
|
|
36740
|
+
const { signature, timestamp } = extractVoiceWebhookSignatureFromHeaders(headers);
|
|
36741
|
+
const result = await verifyVoiceWebhookSignature({
|
|
36742
|
+
body: body ?? "",
|
|
36743
|
+
secret: input.secret,
|
|
36744
|
+
signature,
|
|
36745
|
+
timestamp,
|
|
36746
|
+
toleranceMs: input.toleranceMs
|
|
36747
|
+
});
|
|
36748
|
+
if (!result.ok) {
|
|
36749
|
+
return { allow: false, reason: result.reason, status: 401 };
|
|
36750
|
+
}
|
|
36751
|
+
return { allow: true };
|
|
36752
|
+
};
|
|
36753
|
+
};
|
|
36754
|
+
var isBypassed = (bypassPaths, url) => {
|
|
36755
|
+
for (const path of bypassPaths) {
|
|
36756
|
+
if (url.includes(path))
|
|
36757
|
+
return true;
|
|
36758
|
+
}
|
|
36759
|
+
return false;
|
|
36760
|
+
};
|
|
36761
|
+
var createVoiceRouteAuth = (options) => {
|
|
36762
|
+
const bypassPaths = options.bypassPaths ?? [];
|
|
36763
|
+
return new Elysia53({ name: options.name ?? "voice-route-auth" }).onRequest(async ({ request, set }) => {
|
|
36764
|
+
const url = request.url;
|
|
36765
|
+
if (isBypassed(bypassPaths, url))
|
|
36766
|
+
return;
|
|
36767
|
+
const cloned = request.clone();
|
|
36768
|
+
const body = request.method === "GET" || request.method === "HEAD" ? "" : await cloned.text().catch(() => "");
|
|
36769
|
+
const decision = await Promise.resolve(options.verify({
|
|
36770
|
+
body,
|
|
36771
|
+
headers: request.headers,
|
|
36772
|
+
method: request.method,
|
|
36773
|
+
url
|
|
36774
|
+
}));
|
|
36775
|
+
if (!decision.allow) {
|
|
36776
|
+
set.status = decision.status ?? 401;
|
|
36777
|
+
return new Response(JSON.stringify({ error: decision.reason, ok: false }), {
|
|
36778
|
+
headers: { "content-type": "application/json" },
|
|
36779
|
+
status: decision.status ?? 401
|
|
36780
|
+
});
|
|
36781
|
+
}
|
|
36782
|
+
});
|
|
36783
|
+
};
|
|
36784
|
+
// src/client/costDashboard.ts
|
|
36785
|
+
var padTwo = (value) => String(value).padStart(2, "0");
|
|
36786
|
+
var formatBucketKey = (epochMs, bucketBy) => {
|
|
36787
|
+
const date = new Date(epochMs);
|
|
36788
|
+
const y = date.getUTCFullYear();
|
|
36789
|
+
const m = padTwo(date.getUTCMonth() + 1);
|
|
36790
|
+
const d = padTwo(date.getUTCDate());
|
|
36791
|
+
const h = padTwo(date.getUTCHours());
|
|
36792
|
+
if (bucketBy === "month")
|
|
36793
|
+
return `${y}-${m}`;
|
|
36794
|
+
if (bucketBy === "day")
|
|
36795
|
+
return `${y}-${m}-${d}`;
|
|
36796
|
+
return `${y}-${m}-${d}T${h}`;
|
|
36797
|
+
};
|
|
36798
|
+
var isCostBreakdown = (value) => Boolean(value) && typeof value === "object" && typeof value.totalUsd === "number";
|
|
36799
|
+
var emptyBucket = (bucketKey2) => ({
|
|
36800
|
+
bucketKey: bucketKey2,
|
|
36801
|
+
callCount: 0,
|
|
36802
|
+
llmUsd: 0,
|
|
36803
|
+
sttUsd: 0,
|
|
36804
|
+
telephonyMinutes: 0,
|
|
36805
|
+
telephonyUsd: 0,
|
|
36806
|
+
totalUsd: 0,
|
|
36807
|
+
ttsUsd: 0
|
|
36808
|
+
});
|
|
36809
|
+
var accumulate = (bucket, payload) => {
|
|
36810
|
+
bucket.callCount += 1;
|
|
36811
|
+
bucket.llmUsd += payload.llm.usd;
|
|
36812
|
+
bucket.sttUsd += payload.stt.usd;
|
|
36813
|
+
bucket.ttsUsd += payload.tts.usd;
|
|
36814
|
+
bucket.telephonyUsd += payload.telephony.usd;
|
|
36815
|
+
bucket.telephonyMinutes += payload.telephony.minutes;
|
|
36816
|
+
bucket.totalUsd += payload.totalUsd;
|
|
36817
|
+
};
|
|
36818
|
+
var roundCurrency = (bucket) => {
|
|
36819
|
+
bucket.llmUsd = Math.round(bucket.llmUsd * 1e6) / 1e6;
|
|
36820
|
+
bucket.sttUsd = Math.round(bucket.sttUsd * 1e6) / 1e6;
|
|
36821
|
+
bucket.ttsUsd = Math.round(bucket.ttsUsd * 1e6) / 1e6;
|
|
36822
|
+
bucket.telephonyUsd = Math.round(bucket.telephonyUsd * 1e6) / 1e6;
|
|
36823
|
+
bucket.totalUsd = Math.round(bucket.totalUsd * 1e6) / 1e6;
|
|
36824
|
+
};
|
|
36825
|
+
var buildVoiceCostDashboardReport = (options) => {
|
|
36826
|
+
const bucketBy = options.bucketBy ?? "day";
|
|
36827
|
+
const fromMs = options.fromMs ?? Number.NEGATIVE_INFINITY;
|
|
36828
|
+
const toMs = options.toMs ?? Number.POSITIVE_INFINITY;
|
|
36829
|
+
const buckets = new Map;
|
|
36830
|
+
const grandTotal = emptyBucket("total");
|
|
36831
|
+
let minMs = Number.POSITIVE_INFINITY;
|
|
36832
|
+
let maxMs = Number.NEGATIVE_INFINITY;
|
|
36833
|
+
for (const event of options.events) {
|
|
36834
|
+
if (event.type !== "cost.ready")
|
|
36835
|
+
continue;
|
|
36836
|
+
if (event.at < fromMs || event.at > toMs)
|
|
36837
|
+
continue;
|
|
36838
|
+
if (!isCostBreakdown(event.payload))
|
|
36839
|
+
continue;
|
|
36840
|
+
minMs = Math.min(minMs, event.at);
|
|
36841
|
+
maxMs = Math.max(maxMs, event.at);
|
|
36842
|
+
const bucketKey2 = formatBucketKey(event.at, bucketBy);
|
|
36843
|
+
let bucket = buckets.get(bucketKey2);
|
|
36844
|
+
if (!bucket) {
|
|
36845
|
+
bucket = emptyBucket(bucketKey2);
|
|
36846
|
+
buckets.set(bucketKey2, bucket);
|
|
36847
|
+
}
|
|
36848
|
+
accumulate(bucket, event.payload);
|
|
36849
|
+
accumulate(grandTotal, event.payload);
|
|
36850
|
+
}
|
|
36851
|
+
for (const bucket of buckets.values()) {
|
|
36852
|
+
roundCurrency(bucket);
|
|
36853
|
+
}
|
|
36854
|
+
roundCurrency(grandTotal);
|
|
36855
|
+
return {
|
|
36856
|
+
buckets: Array.from(buckets.values()).sort((a, b) => a.bucketKey.localeCompare(b.bucketKey)),
|
|
36857
|
+
generatedAt: Date.now(),
|
|
36858
|
+
grandTotal,
|
|
36859
|
+
windowEndMs: Number.isFinite(maxMs) ? maxMs : 0,
|
|
36860
|
+
windowStartMs: Number.isFinite(minMs) ? minMs : 0
|
|
36861
|
+
};
|
|
36862
|
+
};
|
|
36863
|
+
// src/client/liveCallViewer.ts
|
|
36864
|
+
var EVENT_BUFFER_LIMIT = 200;
|
|
36865
|
+
var createLiveCallViewer = (options) => {
|
|
36866
|
+
const bufferLimit = options.bufferLimit ?? EVENT_BUFFER_LIMIT;
|
|
36867
|
+
const subscribers = new Set;
|
|
36868
|
+
let state = {
|
|
36869
|
+
agentState: "idle",
|
|
36870
|
+
callDurationMs: 0,
|
|
36871
|
+
events: [],
|
|
36872
|
+
isConnected: true,
|
|
36873
|
+
isLiveListening: true,
|
|
36874
|
+
partialTranscript: "",
|
|
36875
|
+
sessionId: options.sessionId
|
|
36876
|
+
};
|
|
36877
|
+
const startedAt = options.startedAt ?? Date.now();
|
|
36878
|
+
const notify = () => {
|
|
36879
|
+
for (const subscriber of subscribers)
|
|
36880
|
+
subscriber();
|
|
36881
|
+
};
|
|
36882
|
+
const update = (next) => {
|
|
36883
|
+
state = { ...state, ...next };
|
|
36884
|
+
state.callDurationMs = Math.max(0, Date.now() - startedAt);
|
|
36885
|
+
state.agentState = deriveVoiceAgentUIState({
|
|
36886
|
+
hasActivePartial: state.partialTranscript.length > 0,
|
|
36887
|
+
isConnected: state.isConnected,
|
|
36888
|
+
isPlaying: false,
|
|
36889
|
+
isRecording: state.isLiveListening,
|
|
36890
|
+
lastAssistantAt: state.lastAssistantAt,
|
|
36891
|
+
lastTranscriptAt: state.lastTranscriptAt
|
|
36892
|
+
});
|
|
36893
|
+
notify();
|
|
36894
|
+
};
|
|
36895
|
+
const pushEvent = (event) => {
|
|
36896
|
+
const next = state.events.concat(event);
|
|
36897
|
+
if (next.length > bufferLimit) {
|
|
36898
|
+
next.splice(0, next.length - bufferLimit);
|
|
36899
|
+
}
|
|
36900
|
+
update({ events: next });
|
|
36901
|
+
};
|
|
36902
|
+
return {
|
|
36903
|
+
applyControl: (control) => {
|
|
36904
|
+
pushEvent({
|
|
36905
|
+
at: Date.now(),
|
|
36906
|
+
detail: control.reason,
|
|
36907
|
+
kind: "lifecycle",
|
|
36908
|
+
title: `control:${control.type}`
|
|
36909
|
+
});
|
|
36910
|
+
},
|
|
36911
|
+
applyEvent: pushEvent,
|
|
36912
|
+
applyMonitorEvent: ({ payload, type }) => {
|
|
36913
|
+
pushEvent({
|
|
36914
|
+
at: Date.now(),
|
|
36915
|
+
detail: JSON.stringify(payload).slice(0, 240),
|
|
36916
|
+
kind: type === "call.lifecycle" ? "lifecycle" : "lifecycle",
|
|
36917
|
+
title: type
|
|
36918
|
+
});
|
|
36919
|
+
},
|
|
36920
|
+
getState: () => state,
|
|
36921
|
+
noteAgentAudio: (at) => {
|
|
36922
|
+
const ts = at ?? Date.now();
|
|
36923
|
+
update({ lastAssistantAt: ts });
|
|
36924
|
+
pushEvent({
|
|
36925
|
+
at: ts,
|
|
36926
|
+
kind: "agent_audio",
|
|
36927
|
+
title: "Agent audio frame"
|
|
36928
|
+
});
|
|
36929
|
+
},
|
|
36930
|
+
notePartial: (text, at) => {
|
|
36931
|
+
update({ partialTranscript: text });
|
|
36932
|
+
if (text) {
|
|
36933
|
+
pushEvent({
|
|
36934
|
+
at: at ?? Date.now(),
|
|
36935
|
+
detail: text,
|
|
36936
|
+
kind: "transcript",
|
|
36937
|
+
title: "Partial"
|
|
36938
|
+
});
|
|
36939
|
+
}
|
|
36940
|
+
},
|
|
36941
|
+
noteTranscript: (text, at) => {
|
|
36942
|
+
const ts = at ?? Date.now();
|
|
36943
|
+
update({ lastTranscriptAt: ts, partialTranscript: "" });
|
|
36944
|
+
pushEvent({
|
|
36945
|
+
at: ts,
|
|
36946
|
+
detail: text,
|
|
36947
|
+
kind: "transcript",
|
|
36948
|
+
title: "Final transcript"
|
|
36949
|
+
});
|
|
36950
|
+
},
|
|
36951
|
+
reset: (sessionId, startedAtOverride) => {
|
|
36952
|
+
state = {
|
|
36953
|
+
agentState: "idle",
|
|
36954
|
+
callDurationMs: 0,
|
|
36955
|
+
events: [],
|
|
36956
|
+
isConnected: true,
|
|
36957
|
+
isLiveListening: true,
|
|
36958
|
+
partialTranscript: "",
|
|
36959
|
+
sessionId
|
|
36960
|
+
};
|
|
36961
|
+
if (typeof startedAtOverride === "number") {}
|
|
36962
|
+
notify();
|
|
36963
|
+
},
|
|
36964
|
+
subscribe: (subscriber) => {
|
|
36965
|
+
subscribers.add(subscriber);
|
|
36966
|
+
return () => subscribers.delete(subscriber);
|
|
36967
|
+
}
|
|
36968
|
+
};
|
|
36969
|
+
};
|
|
36970
|
+
// src/client/replayTimeline.ts
|
|
36971
|
+
var categorize = (entry) => {
|
|
36972
|
+
const event = entry.event.toLowerCase();
|
|
36973
|
+
if (event.startsWith("stt.") || event.includes("user"))
|
|
36974
|
+
return "user";
|
|
36975
|
+
if (event.startsWith("tts.") || event.includes("assistant") || event.includes("agent"))
|
|
36976
|
+
return "agent";
|
|
36977
|
+
if (event.startsWith("tool.") || event.includes("tool"))
|
|
36978
|
+
return "tool";
|
|
36979
|
+
return "lifecycle";
|
|
36980
|
+
};
|
|
36981
|
+
var buildReplayTimelineReport = (input) => {
|
|
36982
|
+
const events = [];
|
|
36983
|
+
let summaryAgentTurns = 0;
|
|
36984
|
+
let summaryUserTurns = 0;
|
|
36985
|
+
let summaryToolCalls = 0;
|
|
36986
|
+
for (const entry of input.artifact.timeline ?? []) {
|
|
36987
|
+
const category = categorize(entry);
|
|
36988
|
+
if (category === "user")
|
|
36989
|
+
summaryUserTurns += 1;
|
|
36990
|
+
if (category === "agent")
|
|
36991
|
+
summaryAgentTurns += 1;
|
|
36992
|
+
if (category === "tool")
|
|
36993
|
+
summaryToolCalls += 1;
|
|
36994
|
+
events.push({
|
|
36995
|
+
at: entry.atMs,
|
|
36996
|
+
category,
|
|
36997
|
+
detail: entry.text ?? entry.reason,
|
|
36998
|
+
durationMs: entry.chunkDurationMs,
|
|
36999
|
+
label: entry.event
|
|
37000
|
+
});
|
|
37001
|
+
}
|
|
37002
|
+
events.sort((a, b) => a.at - b.at);
|
|
37003
|
+
const first = events[0]?.at ?? 0;
|
|
37004
|
+
const last = events.at(-1)?.at ?? first;
|
|
37005
|
+
return {
|
|
37006
|
+
duration: last - first,
|
|
37007
|
+
events,
|
|
37008
|
+
metadata: {
|
|
37009
|
+
artifactId: input.artifact.id ?? "",
|
|
37010
|
+
title: input.artifact.title
|
|
37011
|
+
},
|
|
37012
|
+
startedAt: first,
|
|
37013
|
+
summary: {
|
|
37014
|
+
agentTurns: summaryAgentTurns,
|
|
37015
|
+
toolCalls: summaryToolCalls,
|
|
37016
|
+
userTurns: summaryUserTurns
|
|
37017
|
+
}
|
|
37018
|
+
};
|
|
37019
|
+
};
|
|
37020
|
+
// src/retention.ts
|
|
37021
|
+
var defaultResolveAt = (event) => {
|
|
37022
|
+
if (!event || typeof event !== "object")
|
|
37023
|
+
return;
|
|
37024
|
+
const value = event.at;
|
|
37025
|
+
return typeof value === "number" ? value : undefined;
|
|
37026
|
+
};
|
|
37027
|
+
var purgeVoiceRetentionStore = async (store, options, now = Date.now()) => {
|
|
37028
|
+
const resolveAt = options.resolveAt ?? defaultResolveAt;
|
|
37029
|
+
const cutoff = now - Math.max(0, options.maxAgeMs);
|
|
37030
|
+
const records = await Promise.resolve(store.list());
|
|
37031
|
+
const purgedIds = [];
|
|
37032
|
+
let attempted = 0;
|
|
37033
|
+
let removed = 0;
|
|
37034
|
+
let failed = 0;
|
|
37035
|
+
for (const record of records) {
|
|
37036
|
+
const at = resolveAt(record);
|
|
37037
|
+
if (typeof at !== "number" || at >= cutoff)
|
|
37038
|
+
continue;
|
|
37039
|
+
attempted += 1;
|
|
37040
|
+
try {
|
|
37041
|
+
await Promise.resolve(store.remove(record.id));
|
|
37042
|
+
purgedIds.push(record.id);
|
|
37043
|
+
removed += 1;
|
|
37044
|
+
} catch {
|
|
37045
|
+
failed += 1;
|
|
37046
|
+
}
|
|
37047
|
+
}
|
|
37048
|
+
return { attempted, failed, purgedIds, reason: "expired", removed };
|
|
37049
|
+
};
|
|
37050
|
+
var createVoiceRetentionScheduler = (options) => {
|
|
37051
|
+
const intervalMs = Math.max(60000, options.intervalMs ?? 6 * 60 * 60000);
|
|
37052
|
+
let timer;
|
|
37053
|
+
const run = async () => {
|
|
37054
|
+
const report = await purgeVoiceRetentionStore(options.store, options.policy);
|
|
37055
|
+
options.onReport?.(report);
|
|
37056
|
+
};
|
|
37057
|
+
return {
|
|
37058
|
+
start: () => {
|
|
37059
|
+
if (timer)
|
|
37060
|
+
return;
|
|
37061
|
+
timer = setInterval(() => {
|
|
37062
|
+
run();
|
|
37063
|
+
}, intervalMs);
|
|
37064
|
+
},
|
|
37065
|
+
stop: () => {
|
|
37066
|
+
if (!timer)
|
|
37067
|
+
return;
|
|
37068
|
+
clearInterval(timer);
|
|
37069
|
+
timer = undefined;
|
|
37070
|
+
}
|
|
37071
|
+
};
|
|
37072
|
+
};
|
|
36484
37073
|
// src/vapiAdapter.ts
|
|
36485
37074
|
var VAPI_BUILT_IN_VARIABLES = {
|
|
36486
37075
|
date: () => new Date().toISOString().slice(0, 10),
|
|
@@ -37064,7 +37653,7 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
37064
37653
|
return report;
|
|
37065
37654
|
};
|
|
37066
37655
|
// src/turnLatency.ts
|
|
37067
|
-
import { Elysia as
|
|
37656
|
+
import { Elysia as Elysia54 } from "elysia";
|
|
37068
37657
|
var DEFAULT_WARN_AFTER_MS2 = 1800;
|
|
37069
37658
|
var DEFAULT_FAIL_AFTER_MS2 = 3200;
|
|
37070
37659
|
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
@@ -37224,7 +37813,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
37224
37813
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
37225
37814
|
const path = options.path ?? "/api/turn-latency";
|
|
37226
37815
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
37227
|
-
const routes = new
|
|
37816
|
+
const routes = new Elysia54({
|
|
37228
37817
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
37229
37818
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
37230
37819
|
if (htmlPath) {
|
|
@@ -37233,7 +37822,7 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
37233
37822
|
return routes;
|
|
37234
37823
|
};
|
|
37235
37824
|
// src/liveLatency.ts
|
|
37236
|
-
import { Elysia as
|
|
37825
|
+
import { Elysia as Elysia55 } from "elysia";
|
|
37237
37826
|
var escapeHtml51 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
37238
37827
|
var percentile6 = (values, percentileValue) => {
|
|
37239
37828
|
if (values.length === 0) {
|
|
@@ -37307,7 +37896,7 @@ await traceStore.append({
|
|
|
37307
37896
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
37308
37897
|
const path = options.path ?? "/api/live-latency";
|
|
37309
37898
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
37310
|
-
const routes = new
|
|
37899
|
+
const routes = new Elysia55({
|
|
37311
37900
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
37312
37901
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
37313
37902
|
if (htmlPath) {
|
|
@@ -37324,7 +37913,7 @@ var createVoiceLiveLatencyRoutes = (options) => {
|
|
|
37324
37913
|
return routes;
|
|
37325
37914
|
};
|
|
37326
37915
|
// src/turnQuality.ts
|
|
37327
|
-
import { Elysia as
|
|
37916
|
+
import { Elysia as Elysia56 } from "elysia";
|
|
37328
37917
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
37329
37918
|
var escapeHtml52 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
37330
37919
|
var getTurnLatencyMs = (turn) => {
|
|
@@ -37430,7 +38019,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
37430
38019
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
37431
38020
|
const path = options.path ?? "/api/turn-quality";
|
|
37432
38021
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
37433
|
-
const routes = new
|
|
38022
|
+
const routes = new Elysia56({
|
|
37434
38023
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
37435
38024
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
37436
38025
|
if (htmlPath) {
|
|
@@ -37439,10 +38028,10 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
37439
38028
|
return routes;
|
|
37440
38029
|
};
|
|
37441
38030
|
// src/phoneAgent.ts
|
|
37442
|
-
import { Elysia as
|
|
38031
|
+
import { Elysia as Elysia58 } from "elysia";
|
|
37443
38032
|
|
|
37444
38033
|
// src/phoneAgentProductionSmoke.ts
|
|
37445
|
-
import { Elysia as
|
|
38034
|
+
import { Elysia as Elysia57 } from "elysia";
|
|
37446
38035
|
var defaultRequirements = [
|
|
37447
38036
|
"media-started",
|
|
37448
38037
|
"transcript",
|
|
@@ -37585,7 +38174,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
37585
38174
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
37586
38175
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
37587
38176
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
37588
|
-
const routes = new
|
|
38177
|
+
const routes = new Elysia57({
|
|
37589
38178
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
37590
38179
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
37591
38180
|
if (htmlPath) {
|
|
@@ -37916,7 +38505,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
37916
38505
|
setupPath: resolveSetupPath(carrier),
|
|
37917
38506
|
smokePath: resolveSmokePath(carrier)
|
|
37918
38507
|
}));
|
|
37919
|
-
const app = new
|
|
38508
|
+
const app = new Elysia58({
|
|
37920
38509
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
37921
38510
|
});
|
|
37922
38511
|
for (const carrier of options.carriers) {
|
|
@@ -39725,7 +40314,7 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
39725
40314
|
};
|
|
39726
40315
|
};
|
|
39727
40316
|
// src/providerCapabilities.ts
|
|
39728
|
-
import { Elysia as
|
|
40317
|
+
import { Elysia as Elysia59 } from "elysia";
|
|
39729
40318
|
var escapeHtml55 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
39730
40319
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
39731
40320
|
configured: true,
|
|
@@ -39828,7 +40417,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
39828
40417
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
39829
40418
|
const path = options.path ?? "/api/provider-capabilities";
|
|
39830
40419
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
39831
|
-
const routes = new
|
|
40420
|
+
const routes = new Elysia59({
|
|
39832
40421
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
39833
40422
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
39834
40423
|
if (htmlPath) {
|
|
@@ -39837,7 +40426,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
39837
40426
|
return routes;
|
|
39838
40427
|
};
|
|
39839
40428
|
// src/providerOrchestration.ts
|
|
39840
|
-
import { Elysia as
|
|
40429
|
+
import { Elysia as Elysia60 } from "elysia";
|
|
39841
40430
|
var defaultRequirement = {
|
|
39842
40431
|
minProviders: 1,
|
|
39843
40432
|
requireBudgetPolicy: false,
|
|
@@ -40013,7 +40602,7 @@ var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
|
40013
40602
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
40014
40603
|
const htmlPath = options.htmlPath === undefined ? "/voice/provider-orchestration" : options.htmlPath;
|
|
40015
40604
|
const markdownPath = options.markdownPath === undefined ? "/voice/provider-orchestration.md" : options.markdownPath;
|
|
40016
|
-
const routes = new
|
|
40605
|
+
const routes = new Elysia60({
|
|
40017
40606
|
name: options.name ?? "absolutejs-voice-provider-orchestration"
|
|
40018
40607
|
}).get(path, () => buildVoiceProviderOrchestrationReport(options));
|
|
40019
40608
|
if (htmlPath) {
|
|
@@ -40186,7 +40775,7 @@ var assertVoiceProviderRoutingContractEvidence = (reports, input = {}) => {
|
|
|
40186
40775
|
return report;
|
|
40187
40776
|
};
|
|
40188
40777
|
// src/voiceMonitoring.ts
|
|
40189
|
-
import { Elysia as
|
|
40778
|
+
import { Elysia as Elysia61 } from "elysia";
|
|
40190
40779
|
var escapeHtml57 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
40191
40780
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
40192
40781
|
var rollupStatus5 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
@@ -40471,7 +41060,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
40471
41060
|
monitors: options.monitors,
|
|
40472
41061
|
now: options.now
|
|
40473
41062
|
});
|
|
40474
|
-
const routes = new
|
|
41063
|
+
const routes = new Elysia61({
|
|
40475
41064
|
name: options.name ?? "absolutejs-voice-monitoring"
|
|
40476
41065
|
}).get(path, report).get(`${path}.md`, async () => {
|
|
40477
41066
|
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
@@ -40518,7 +41107,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
40518
41107
|
};
|
|
40519
41108
|
var createVoiceMonitorRunnerRoutes = (options) => {
|
|
40520
41109
|
const path = options.path ?? "/api/voice/monitor-runner";
|
|
40521
|
-
return new
|
|
41110
|
+
return new Elysia61({
|
|
40522
41111
|
name: options.name ?? "absolutejs-voice-monitor-runner"
|
|
40523
41112
|
}).get(path, () => ({
|
|
40524
41113
|
isRunning: options.runner.isRunning()
|
|
@@ -40906,7 +41495,7 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
40906
41495
|
};
|
|
40907
41496
|
};
|
|
40908
41497
|
// src/providerStackRecommendations.ts
|
|
40909
|
-
import { Elysia as
|
|
41498
|
+
import { Elysia as Elysia62 } from "elysia";
|
|
40910
41499
|
var escapeHtml58 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
40911
41500
|
var profileProviderPriorities = {
|
|
40912
41501
|
"meeting-recorder": {
|
|
@@ -41268,7 +41857,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
41268
41857
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
41269
41858
|
const path = options.path ?? "/api/provider-contracts";
|
|
41270
41859
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
41271
|
-
const routes = new
|
|
41860
|
+
const routes = new Elysia62({
|
|
41272
41861
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
41273
41862
|
});
|
|
41274
41863
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -41386,7 +41975,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
41386
41975
|
return assertion;
|
|
41387
41976
|
};
|
|
41388
41977
|
// src/opsConsoleRoutes.ts
|
|
41389
|
-
import { Elysia as
|
|
41978
|
+
import { Elysia as Elysia63 } from "elysia";
|
|
41390
41979
|
var DEFAULT_LINKS = [
|
|
41391
41980
|
{
|
|
41392
41981
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -41503,7 +42092,7 @@ var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
|
41503
42092
|
};
|
|
41504
42093
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
41505
42094
|
const path = options.path ?? "/ops-console";
|
|
41506
|
-
const routes = new
|
|
42095
|
+
const routes = new Elysia63({
|
|
41507
42096
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
41508
42097
|
});
|
|
41509
42098
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -41520,7 +42109,7 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
41520
42109
|
return routes;
|
|
41521
42110
|
};
|
|
41522
42111
|
// src/incidentBundle.ts
|
|
41523
|
-
import { Elysia as
|
|
42112
|
+
import { Elysia as Elysia64 } from "elysia";
|
|
41524
42113
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
41525
42114
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
41526
42115
|
return false;
|
|
@@ -41737,7 +42326,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
41737
42326
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
41738
42327
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
41739
42328
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
41740
|
-
const routes = new
|
|
42329
|
+
const routes = new Elysia64({
|
|
41741
42330
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
41742
42331
|
});
|
|
41743
42332
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -41938,7 +42527,7 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
41938
42527
|
};
|
|
41939
42528
|
};
|
|
41940
42529
|
// src/opsStatusRoutes.ts
|
|
41941
|
-
import { Elysia as
|
|
42530
|
+
import { Elysia as Elysia65 } from "elysia";
|
|
41942
42531
|
var escapeHtml60 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
41943
42532
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
41944
42533
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
@@ -41950,7 +42539,7 @@ var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
|
41950
42539
|
};
|
|
41951
42540
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
41952
42541
|
const path = options.path ?? "/api/voice/ops-status";
|
|
41953
|
-
const routes = new
|
|
42542
|
+
const routes = new Elysia65({
|
|
41954
42543
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
41955
42544
|
});
|
|
41956
42545
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -42383,7 +42972,7 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
42383
42972
|
};
|
|
42384
42973
|
};
|
|
42385
42974
|
// src/traceDeliveryRoutes.ts
|
|
42386
|
-
import { Elysia as
|
|
42975
|
+
import { Elysia as Elysia66 } from "elysia";
|
|
42387
42976
|
var escapeHtml61 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
42388
42977
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
42389
42978
|
var getNumber12 = (value) => {
|
|
@@ -42492,7 +43081,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
42492
43081
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
42493
43082
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
42494
43083
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
42495
|
-
const routes = new
|
|
43084
|
+
const routes = new Elysia66({
|
|
42496
43085
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
42497
43086
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
42498
43087
|
if (htmlPath !== false) {
|
|
@@ -42645,7 +43234,7 @@ var createVoiceMemoryStore = () => {
|
|
|
42645
43234
|
return { get, getOrCreate, list, remove, set };
|
|
42646
43235
|
};
|
|
42647
43236
|
// src/opsWebhook.ts
|
|
42648
|
-
import { Elysia as
|
|
43237
|
+
import { Elysia as Elysia67 } from "elysia";
|
|
42649
43238
|
var toHex7 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
42650
43239
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
42651
43240
|
const encoder2 = new TextEncoder;
|
|
@@ -42775,7 +43364,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
42775
43364
|
};
|
|
42776
43365
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
42777
43366
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
42778
|
-
return new
|
|
43367
|
+
return new Elysia67().post(path, async ({ body, request, set }) => {
|
|
42779
43368
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
42780
43369
|
if (options.signingSecret) {
|
|
42781
43370
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -43230,7 +43819,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
43230
43819
|
};
|
|
43231
43820
|
};
|
|
43232
43821
|
// src/postCallAnalysis.ts
|
|
43233
|
-
import { Elysia as
|
|
43822
|
+
import { Elysia as Elysia68 } from "elysia";
|
|
43234
43823
|
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
43235
43824
|
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
43236
43825
|
var getPathValue3 = (source, path) => {
|
|
@@ -43409,7 +43998,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
|
|
|
43409
43998
|
};
|
|
43410
43999
|
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
43411
44000
|
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
43412
|
-
const routes = new
|
|
44001
|
+
const routes = new Elysia68({
|
|
43413
44002
|
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
43414
44003
|
});
|
|
43415
44004
|
routes.get(path, async ({ query }) => {
|
|
@@ -43434,7 +44023,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
|
43434
44023
|
return routes;
|
|
43435
44024
|
};
|
|
43436
44025
|
// src/guardrails.ts
|
|
43437
|
-
import { Elysia as
|
|
44026
|
+
import { Elysia as Elysia69 } from "elysia";
|
|
43438
44027
|
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
43439
44028
|
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
43440
44029
|
var matchesRule = async (rule, input) => {
|
|
@@ -43736,7 +44325,7 @@ var resolveGuardrailReport = async (options, input) => {
|
|
|
43736
44325
|
};
|
|
43737
44326
|
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
43738
44327
|
const path = options.path ?? "/api/voice/guardrails";
|
|
43739
|
-
const routes = new
|
|
44328
|
+
const routes = new Elysia69({
|
|
43740
44329
|
name: options.name ?? "absolutejs-voice-guardrails"
|
|
43741
44330
|
});
|
|
43742
44331
|
routes.all(path, async ({ request }) => {
|
|
@@ -44515,7 +45104,7 @@ var shapeTelephonyAssistantText = (text, options = {}) => {
|
|
|
44515
45104
|
return ensureTerminalPunctuation(normalizeWhitespace(limitedChars));
|
|
44516
45105
|
};
|
|
44517
45106
|
// src/proofPack.ts
|
|
44518
|
-
import { Elysia as
|
|
45107
|
+
import { Elysia as Elysia70 } from "elysia";
|
|
44519
45108
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
44520
45109
|
import { dirname as dirname3, join as join4 } from "path";
|
|
44521
45110
|
var toGeneratedAt = (value) => value === undefined ? new Date().toISOString() : typeof value === "number" ? new Date(value).toISOString() : value;
|
|
@@ -45101,7 +45690,7 @@ var createVoiceProofPackArtifacts = (input) => [
|
|
|
45101
45690
|
var createVoiceProofPackRoutes = (options) => {
|
|
45102
45691
|
const jsonPath = options.jsonPath ?? "/api/voice/proof-pack";
|
|
45103
45692
|
const markdownPath = options.markdownPath ?? "/voice/proof-pack.md";
|
|
45104
|
-
const app = new
|
|
45693
|
+
const app = new Elysia70({ name: options.name ?? "voice-proof-pack" });
|
|
45105
45694
|
if (jsonPath !== false) {
|
|
45106
45695
|
app.get(jsonPath, async () => new Response(JSON.stringify(await resolveProofPack(options.source), null, 2), {
|
|
45107
45696
|
headers: {
|
|
@@ -46202,7 +46791,7 @@ var buildVoiceMultilingualProofReadinessCheck = (report, options = {}) => {
|
|
|
46202
46791
|
};
|
|
46203
46792
|
};
|
|
46204
46793
|
// src/monitor.ts
|
|
46205
|
-
import { Elysia as
|
|
46794
|
+
import { Elysia as Elysia71 } from "elysia";
|
|
46206
46795
|
var buildAudioFanout = () => {
|
|
46207
46796
|
const handlers = new Set;
|
|
46208
46797
|
return {
|
|
@@ -46491,7 +47080,7 @@ var createVoiceLiveMonitorRoutes = (options) => {
|
|
|
46491
47080
|
transfer: options.controlHandlers?.transfer ?? buildDefaultControlHandler("transfer"),
|
|
46492
47081
|
voicemail: options.controlHandlers?.voicemail ?? buildDefaultControlHandler("voicemail")
|
|
46493
47082
|
};
|
|
46494
|
-
const app = new
|
|
47083
|
+
const app = new Elysia71({ name: "absolutejs-voice-monitor" });
|
|
46495
47084
|
const unsubscribers = new WeakMap;
|
|
46496
47085
|
if (listenPath !== false && listenPath.length > 0) {
|
|
46497
47086
|
app.ws(`/${listenPath.replace(/^\/+/, "")}`, {
|
|
@@ -46889,6 +47478,7 @@ export {
|
|
|
46889
47478
|
recommendVoiceProviderStack,
|
|
46890
47479
|
recommendVoiceProfileSwitch,
|
|
46891
47480
|
readVoiceProofTrendReportFile,
|
|
47481
|
+
purgeVoiceRetentionStore,
|
|
46892
47482
|
pruneVoiceTraceEvents,
|
|
46893
47483
|
pruneVoiceIncidentBundleArtifacts,
|
|
46894
47484
|
parseVoiceTelephonyWebhookEvent,
|
|
@@ -46908,6 +47498,7 @@ export {
|
|
|
46908
47498
|
isWithinCampaignWindow,
|
|
46909
47499
|
isVoiceOpsTaskOverdue,
|
|
46910
47500
|
isPhoneOnDNC,
|
|
47501
|
+
interleaveStereoPcm,
|
|
46911
47502
|
importVoiceCampaignRecipients,
|
|
46912
47503
|
heartbeatVoiceOpsTask,
|
|
46913
47504
|
hasVoiceOpsTaskSLABreach,
|
|
@@ -46965,10 +47556,12 @@ export {
|
|
|
46965
47556
|
evaluateVoiceBrowserCallProfileEvidence,
|
|
46966
47557
|
evaluateVoiceAgentSquadContractEvidence,
|
|
46967
47558
|
encodeTwilioMulawBase64,
|
|
47559
|
+
encodeStereoWav,
|
|
46968
47560
|
encodePcmAsWav,
|
|
46969
47561
|
describeVoiceIVRPlan,
|
|
46970
47562
|
describeVoiceAssistantMode,
|
|
46971
47563
|
describeVoiceAgentUIState,
|
|
47564
|
+
deriveVoiceRecordingRedactionRanges,
|
|
46972
47565
|
deriveVoiceAgentUIState,
|
|
46973
47566
|
deliverVoiceTraceEventsToSinks,
|
|
46974
47567
|
deliverVoiceObservabilityExport,
|
|
@@ -46978,6 +47571,7 @@ export {
|
|
|
46978
47571
|
deliverVoiceHandoffDelivery,
|
|
46979
47572
|
deliverVoiceHandoff,
|
|
46980
47573
|
deliverVoiceAuditEventsToSinks,
|
|
47574
|
+
defineVoiceAssistant,
|
|
46981
47575
|
decodeTwilioMulawBase64,
|
|
46982
47576
|
deadLetterVoiceOpsTask,
|
|
46983
47577
|
createVoiceZeroRetentionPolicy,
|
|
@@ -46992,6 +47586,7 @@ export {
|
|
|
46992
47586
|
createVoiceWebhookDeliveryWorkerLoop,
|
|
46993
47587
|
createVoiceWebhookDeliveryWorker,
|
|
46994
47588
|
createVoiceWebhookDeliverySink,
|
|
47589
|
+
createVoiceWavRecordingEncoder,
|
|
46995
47590
|
createVoiceVoicemailDetectionTool,
|
|
46996
47591
|
createVoiceTwilioRedirectHandoffAdapter,
|
|
46997
47592
|
createVoiceTwilioCampaignDialer,
|
|
@@ -47077,7 +47672,9 @@ export {
|
|
|
47077
47672
|
createVoiceS3RecordingStore,
|
|
47078
47673
|
createVoiceS3DeliverySink,
|
|
47079
47674
|
createVoiceRoutingDecisionSummary,
|
|
47675
|
+
createVoiceRouteAuth,
|
|
47080
47676
|
createVoiceReviewSavedEvent,
|
|
47677
|
+
createVoiceRetentionScheduler,
|
|
47081
47678
|
createVoiceResilienceRoutes,
|
|
47082
47679
|
createVoiceRedisTelnyxWebhookEventStore,
|
|
47083
47680
|
createVoiceRedisTelephonyWebhookIdempotencyStore,
|
|
@@ -47226,6 +47823,7 @@ export {
|
|
|
47226
47823
|
createVoiceHandoffDeliveryWorkerLoop,
|
|
47227
47824
|
createVoiceHandoffDeliveryWorker,
|
|
47228
47825
|
createVoiceHandoffDeliveryRecord,
|
|
47826
|
+
createVoiceHMACAuthVerifier,
|
|
47229
47827
|
createVoiceGuardrailRuntime,
|
|
47230
47828
|
createVoiceGuardrailRoutes,
|
|
47231
47829
|
createVoiceGuardrailPolicy,
|
|
@@ -47280,6 +47878,7 @@ export {
|
|
|
47280
47878
|
createVoiceCRMActivitySink,
|
|
47281
47879
|
createVoiceBrowserMediaRoutes,
|
|
47282
47880
|
createVoiceBrowserCallProfileRoutes,
|
|
47881
|
+
createVoiceBearerAuthVerifier,
|
|
47283
47882
|
createVoiceBargeInRoutes,
|
|
47284
47883
|
createVoiceBackchannelDriver,
|
|
47285
47884
|
createVoiceAuditTrailRoutes,
|
|
@@ -47330,7 +47929,9 @@ export {
|
|
|
47330
47929
|
createMemoryVoiceTelnyxWebhookEventStore,
|
|
47331
47930
|
createMemoryVoiceTelephonyWebhookIdempotencyStore,
|
|
47332
47931
|
createMemoryVoicePlivoWebhookNonceStore,
|
|
47932
|
+
createLiveCallViewer,
|
|
47333
47933
|
createJSONVoiceAssistantModel,
|
|
47934
|
+
createInMemoryVoiceCallQuota,
|
|
47334
47935
|
createInMemoryDNCList,
|
|
47335
47936
|
createId,
|
|
47336
47937
|
createGeminiVoiceAssistantModel,
|
|
@@ -47424,6 +48025,7 @@ export {
|
|
|
47424
48025
|
buildVoiceDeliveryRuntimeReport,
|
|
47425
48026
|
buildVoiceDataRetentionPlan,
|
|
47426
48027
|
buildVoiceDataControlReport,
|
|
48028
|
+
buildVoiceCostDashboardReport,
|
|
47427
48029
|
buildVoiceCompetitiveCoverageReport,
|
|
47428
48030
|
buildVoiceCampaignObservabilityReport,
|
|
47429
48031
|
buildVoiceCallerMemoryNamespace,
|
|
@@ -47432,6 +48034,7 @@ export {
|
|
|
47432
48034
|
buildVoiceAuditTrailReport,
|
|
47433
48035
|
buildVoiceAuditExport,
|
|
47434
48036
|
buildVoiceAuditDeliveryReport,
|
|
48037
|
+
buildReplayTimelineReport,
|
|
47435
48038
|
buildOTELTraceId,
|
|
47436
48039
|
buildOTELSpanId,
|
|
47437
48040
|
buildEmptyVoiceProofTrendReport,
|