@absolutejs/voice 0.0.22-beta.163 → 0.0.22-beta.165

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -46,6 +46,7 @@ export { assertVoiceProviderRoutingContract, runVoiceProviderRoutingContract } f
46
46
  export { createVoicePhoneAgentProductionSmokeHTMLHandler, createVoicePhoneAgentProductionSmokeJSONHandler, createVoicePhoneAgentProductionSmokeRoutes, renderVoicePhoneAgentProductionSmokeHTML, runVoicePhoneAgentProductionSmokeContract } from './phoneAgentProductionSmoke';
47
47
  export { buildVoiceProductionReadinessGate, buildVoiceProductionReadinessReport, createVoiceProductionReadinessRoutes, renderVoiceProductionReadinessHTML, summarizeVoiceProductionReadinessGate } from './productionReadiness';
48
48
  export { createVoiceReadinessProfile, recommendVoiceReadinessProfile } from './readinessProfiles';
49
+ export { evaluateVoiceProviderStackGaps, recommendVoiceProviderStack } from './providerStackRecommendations';
49
50
  export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
50
51
  export { summarizeVoiceOpsStatus } from './opsStatus';
51
52
  export { createVoiceOpsStatusRoutes, renderVoiceOpsStatusHTML } from './opsStatusRoutes';
@@ -105,6 +106,7 @@ export type { VoiceOpsConsoleLink, VoiceOpsConsoleReport, VoiceOpsConsoleRoutesO
105
106
  export type { VoiceOpsStatus, VoiceOpsStatusLink, VoiceOpsStatusOptions, VoiceOpsStatusReport, VoiceOpsStatusRoutesOptions } from './opsStatus';
106
107
  export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptions, VoiceProductionReadinessAuditRequirement, VoiceProductionReadinessAuditSummary, VoiceProductionReadinessCheck, VoiceProductionReadinessGateIssue, VoiceProductionReadinessGateOptions, VoiceProductionReadinessGateProfile, VoiceProductionReadinessGateProfileSurface, VoiceProductionReadinessGateReport, VoiceProductionReadinessOpsActionHistoryOptions, VoiceProductionReadinessOpsActionHistorySummary, VoiceProductionReadinessProfileExplanation, VoiceProductionReadinessProfileSurface, VoiceProductionReadinessProofSource, VoiceProductionReadinessReport, VoiceProductionReadinessRoutesOptions, VoiceProductionReadinessTraceDeliverySummary, VoiceProductionReadinessAuditDeliveryOptions, VoiceProductionReadinessAuditDeliverySummary, VoiceProductionReadinessTraceDeliveryOptions, VoiceProductionReadinessStatus } from './productionReadiness';
107
108
  export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
109
+ export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
108
110
  export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
109
111
  export type { VoiceResilienceIOSimulator, VoiceResilienceLink, VoiceResiliencePageData, VoiceResilienceRoutesOptions, VoiceResilienceSimulationProvider, VoiceRoutingKindSummary, VoiceRoutingDecisionSummary, VoiceRoutingDecisionSummaryOptions, VoiceRoutingEvent, VoiceRoutingEventKind, VoiceRoutingSessionSummary, VoiceRoutingSessionSummaryOptions } from './resilienceRoutes';
110
112
  export type { VoiceIOProviderRouterEvent, VoiceIOProviderRouterOptions, VoiceIOProviderRouterPolicy, VoiceIOProviderRouterPolicyConfig, VoiceSTTProviderRouterOptions, VoiceTTSProviderRouterOptions } from './providerAdapters';
package/dist/index.js CHANGED
@@ -20142,6 +20142,7 @@ var readinessGateCodes = {
20142
20142
  "Provider fallback recovery": "voice.readiness.provider_fallback_recovery",
20143
20143
  "Provider health": "voice.readiness.provider_health",
20144
20144
  "Provider routing contracts": "voice.readiness.provider_routing_contracts",
20145
+ "Provider stack capabilities": "voice.readiness.provider_stack_capabilities",
20145
20146
  "Quality gates": "voice.readiness.quality_gates",
20146
20147
  "Reconnect recovery contracts": "voice.readiness.reconnect_contracts",
20147
20148
  "Routing evidence": "voice.readiness.routing_evidence",
@@ -20213,6 +20214,12 @@ var resolveProviderRoutingContracts = async (options, input) => {
20213
20214
  }
20214
20215
  return typeof options.providerRoutingContracts === "function" ? await options.providerRoutingContracts(input) : options.providerRoutingContracts;
20215
20216
  };
20217
+ var resolveProviderStack = async (options, input) => {
20218
+ if (options.providerStack === false || options.providerStack === undefined) {
20219
+ return;
20220
+ }
20221
+ return typeof options.providerStack === "function" ? await options.providerStack(input) : options.providerStack;
20222
+ };
20216
20223
  var resolvePhoneAgentSmokes = async (options, input) => {
20217
20224
  if (options.phoneAgentSmokes === false || options.phoneAgentSmokes === undefined) {
20218
20225
  return;
@@ -20472,6 +20479,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20472
20479
  carriers,
20473
20480
  agentSquadContracts,
20474
20481
  providerRoutingContracts,
20482
+ providerStack,
20475
20483
  phoneAgentSmokes,
20476
20484
  reconnectContracts,
20477
20485
  bargeInReports,
@@ -20502,6 +20510,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20502
20510
  resolveCarriers(options, { query, request }),
20503
20511
  resolveAgentSquadContracts(options, { query, request }),
20504
20512
  resolveProviderRoutingContracts(options, { query, request }),
20513
+ resolveProviderStack(options, { query, request }),
20505
20514
  resolvePhoneAgentSmokes(options, { query, request }),
20506
20515
  resolveReconnectContracts(options, { query, request }),
20507
20516
  resolveBargeInReports(options, { query, request }),
@@ -20695,6 +20704,23 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20695
20704
  ]
20696
20705
  });
20697
20706
  }
20707
+ if (providerStack) {
20708
+ const missingLanes = providerStack.gaps.filter((gap) => gap.status !== "pass");
20709
+ checks.push({
20710
+ detail: providerStack.status === "pass" ? `${providerStack.profile} provider stack has declared capability coverage.` : missingLanes.length > 0 ? missingLanes.map((gap) => gap.provider ? `${gap.kind.toUpperCase()} ${gap.provider} missing ${gap.missing.join(", ")}` : `${gap.kind.toUpperCase()} provider is not configured`).join("; ") + "." : "Provider stack capability coverage needs review.",
20711
+ href: options.links?.providerRoutingContracts ?? options.links?.resilience ?? "/resilience",
20712
+ label: "Provider stack capabilities",
20713
+ status: providerStack.status,
20714
+ value: providerStack.status === "pass" ? "covered" : `${providerStack.missing} missing`,
20715
+ actions: providerStack.status === "pass" ? [] : [
20716
+ {
20717
+ description: "Open provider capabilities and confirm the selected stack covers this readiness profile.",
20718
+ href: options.links?.providerRoutingContracts ?? options.links?.resilience ?? "/resilience",
20719
+ label: "Open provider capabilities"
20720
+ }
20721
+ ]
20722
+ });
20723
+ }
20698
20724
  if (phoneAgentSmokeSummary) {
20699
20725
  checks.push({
20700
20726
  detail: phoneAgentSmokeSummary.status === "pass" ? `${phoneAgentSmokeSummary.passed} phone-agent smoke contract(s) are passing.` : phoneAgentSmokeSummary.total === 0 ? "No phone-agent production smoke contracts are configured." : `${phoneAgentSmokeSummary.failed} phone-agent production smoke contract(s) failed.`,
@@ -20889,6 +20915,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20889
20915
  degraded: degradedProviders,
20890
20916
  total: providers.length
20891
20917
  },
20918
+ providerStack,
20892
20919
  providerRecovery,
20893
20920
  phoneAgentSmokes: phoneAgentSmokeSummary,
20894
20921
  providerRoutingContracts: providerRoutingContractSummary,
@@ -21284,6 +21311,121 @@ var recommendVoiceReadinessProfile = (options) => {
21284
21311
  scores
21285
21312
  };
21286
21313
  };
21314
+ // src/providerStackRecommendations.ts
21315
+ var profileProviderPriorities = {
21316
+ "meeting-recorder": {
21317
+ llm: ["openai", "anthropic", "gemini"],
21318
+ stt: ["deepgram", "assemblyai", "openai"],
21319
+ tts: ["openai", "elevenlabs"]
21320
+ },
21321
+ "ops-heavy": {
21322
+ llm: ["anthropic", "openai", "gemini"],
21323
+ stt: ["deepgram", "assemblyai", "openai"],
21324
+ tts: ["openai", "elevenlabs"]
21325
+ },
21326
+ "phone-agent": {
21327
+ llm: ["openai", "anthropic", "gemini"],
21328
+ stt: ["deepgram", "assemblyai", "openai"],
21329
+ tts: ["openai", "elevenlabs"]
21330
+ }
21331
+ };
21332
+ var profileProviderReasons = {
21333
+ "meeting-recorder": {
21334
+ llm: "meeting-recorder favors strong summarization and extraction quality",
21335
+ stt: "meeting-recorder favors accurate long-form transcription",
21336
+ tts: "meeting-recorder usually needs optional, low-friction spoken playback"
21337
+ },
21338
+ "ops-heavy": {
21339
+ llm: "ops-heavy deployments favor dependable reasoning for review and escalation flows",
21340
+ stt: "ops-heavy deployments keep STT recommendation available for live proof surfaces",
21341
+ tts: "ops-heavy deployments keep TTS recommendation available for operator demos"
21342
+ },
21343
+ "phone-agent": {
21344
+ llm: "phone-agent favors low-latency turn handling and tool orchestration",
21345
+ stt: "phone-agent favors low-latency realtime transcription",
21346
+ tts: "phone-agent favors low-latency spoken response"
21347
+ }
21348
+ };
21349
+ var profileRequiredCapabilities = {
21350
+ "meeting-recorder": {
21351
+ llm: ["JSON result shaping", "summarization"],
21352
+ stt: ["realtime STT", "smart formatting"],
21353
+ tts: ["spoken playback"]
21354
+ },
21355
+ "ops-heavy": {
21356
+ llm: ["tool calling", "JSON result shaping", "fallback routing"],
21357
+ stt: ["realtime STT"],
21358
+ tts: ["spoken playback"]
21359
+ },
21360
+ "phone-agent": {
21361
+ llm: ["tool calling", "JSON result shaping", "fallback routing"],
21362
+ stt: ["realtime STT", "VAD events"],
21363
+ tts: ["streaming speech", "barge-in friendly"]
21364
+ }
21365
+ };
21366
+ var chooseProvider = (available, priorities) => priorities.find((provider) => available.includes(provider)) ?? available[0];
21367
+ var recommendVoiceProviderStack = (input) => {
21368
+ const priorities = profileProviderPriorities[input.profile];
21369
+ const stacks = {};
21370
+ const recommended = {};
21371
+ const reasons = [];
21372
+ for (const kind of ["llm", "stt", "tts"]) {
21373
+ const available = input.providers[kind] ?? [];
21374
+ const provider = chooseProvider(available, priorities[kind]);
21375
+ const alternatives = provider ? available.filter((candidate) => candidate !== provider) : [...available];
21376
+ const kindReasons = [
21377
+ profileProviderReasons[input.profile][kind],
21378
+ provider ? `${provider} is the recommended ${kind.toUpperCase()} provider from the configured set` : `no ${kind.toUpperCase()} providers are configured`
21379
+ ];
21380
+ if (provider) {
21381
+ recommended[kind] = provider;
21382
+ }
21383
+ stacks[kind] = {
21384
+ alternatives,
21385
+ provider,
21386
+ reasons: kindReasons
21387
+ };
21388
+ reasons.push(...kindReasons);
21389
+ }
21390
+ return {
21391
+ profile: input.profile,
21392
+ reasons,
21393
+ recommended,
21394
+ stacks
21395
+ };
21396
+ };
21397
+ var normalizeCapability = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, "");
21398
+ var includesCapability = (capabilities, required) => {
21399
+ const normalizedRequired = normalizeCapability(required);
21400
+ return capabilities.some((capability) => {
21401
+ const normalizedCapability = normalizeCapability(capability);
21402
+ return normalizedCapability === normalizedRequired || normalizedCapability.includes(normalizedRequired) || normalizedRequired.includes(normalizedCapability);
21403
+ });
21404
+ };
21405
+ var evaluateVoiceProviderStackGaps = (input) => {
21406
+ const recommendation = input.recommendation ?? recommendVoiceProviderStack(input);
21407
+ const gaps = ["llm", "stt", "tts"].map((kind) => {
21408
+ const required = input.required?.[kind] ?? profileRequiredCapabilities[input.profile][kind];
21409
+ const provider = recommendation.recommended[kind];
21410
+ const present = provider ? [...input.capabilities?.[kind]?.[provider] ?? []] : [];
21411
+ const missing2 = provider ? required.filter((capability) => !includesCapability(present, capability)) : [...required];
21412
+ return {
21413
+ kind,
21414
+ missing: missing2,
21415
+ present,
21416
+ provider,
21417
+ required: [...required],
21418
+ status: !provider ? "fail" : missing2.length > 0 ? "warn" : "pass"
21419
+ };
21420
+ });
21421
+ const missing = gaps.reduce((total, gap) => total + gap.missing.length, 0);
21422
+ return {
21423
+ gaps,
21424
+ missing,
21425
+ profile: input.profile,
21426
+ status: gaps.some((gap) => gap.status === "fail") ? "fail" : gaps.some((gap) => gap.status === "warn") ? "warn" : "pass"
21427
+ };
21428
+ };
21287
21429
  // src/opsConsoleRoutes.ts
21288
21430
  import { Elysia as Elysia34 } from "elysia";
21289
21431
  var DEFAULT_LINKS = [
@@ -24100,6 +24242,7 @@ export {
24100
24242
  recordVoiceHandoffAuditEvent,
24101
24243
  recordVoiceAuditEvent,
24102
24244
  recommendVoiceReadinessProfile,
24245
+ recommendVoiceProviderStack,
24103
24246
  pruneVoiceTraceEvents,
24104
24247
  parseVoiceTelephonyWebhookEvent,
24105
24248
  matchesVoiceOpsTaskAssignmentRule,
@@ -24118,6 +24261,7 @@ export {
24118
24261
  evaluateVoiceTrace,
24119
24262
  evaluateVoiceTelephonyContract,
24120
24263
  evaluateVoiceQuality,
24264
+ evaluateVoiceProviderStackGaps,
24121
24265
  encodeTwilioMulawBase64,
24122
24266
  deliverVoiceTraceEventsToSinks,
24123
24267
  deliverVoiceIntegrationEventToSinks,
@@ -11,6 +11,7 @@ import type { VoicePhoneAgentProductionSmokeReport } from './phoneAgentProductio
11
11
  import type { VoiceReconnectContractReport } from './reconnectContract';
12
12
  import type { VoiceAuditEventStore, VoiceAuditEventType, VoiceAuditOutcome } from './audit';
13
13
  import { type VoiceAuditSinkDeliveryStore } from './auditSinks';
14
+ import type { VoiceProviderStackCapabilityGapReport } from './providerStackRecommendations';
14
15
  export type VoiceProductionReadinessStatus = 'fail' | 'pass' | 'warn';
15
16
  export type VoiceProductionReadinessAction = {
16
17
  description?: string;
@@ -137,6 +138,7 @@ export type VoiceProductionReadinessReport = {
137
138
  degraded: number;
138
139
  total: number;
139
140
  };
141
+ providerStack?: VoiceProviderStackCapabilityGapReport;
140
142
  providerRecovery: VoiceProviderFallbackRecoverySummary;
141
143
  phoneAgentSmokes?: {
142
144
  failed: number;
@@ -297,6 +299,10 @@ export type VoiceProductionReadinessRoutesOptions = {
297
299
  query: Record<string, unknown>;
298
300
  request: Request;
299
301
  }) => Promise<readonly VoiceProviderRoutingContractReport[]> | readonly VoiceProviderRoutingContractReport[]);
302
+ providerStack?: false | VoiceProviderStackCapabilityGapReport | ((input: {
303
+ query: Record<string, unknown>;
304
+ request: Request;
305
+ }) => Promise<VoiceProviderStackCapabilityGapReport> | VoiceProviderStackCapabilityGapReport);
300
306
  reconnectContracts?: false | readonly VoiceReconnectContractReport[] | ((input: {
301
307
  query: Record<string, unknown>;
302
308
  request: Request;
@@ -0,0 +1,39 @@
1
+ import type { VoiceReadinessProfileName } from './readinessProfiles';
2
+ export type VoiceProviderStackKind = 'llm' | 'stt' | 'tts';
3
+ export type VoiceProviderStackInput<TProvider extends string = string> = {
4
+ profile: VoiceReadinessProfileName;
5
+ providers: Partial<Record<VoiceProviderStackKind, readonly TProvider[]>>;
6
+ };
7
+ export type VoiceProviderStackChoice<TProvider extends string = string> = {
8
+ alternatives: TProvider[];
9
+ provider?: TProvider;
10
+ reasons: string[];
11
+ };
12
+ export type VoiceProviderStackRecommendation<TProvider extends string = string> = {
13
+ profile: VoiceReadinessProfileName;
14
+ reasons: string[];
15
+ recommended: Partial<Record<VoiceProviderStackKind, TProvider>>;
16
+ stacks: Partial<Record<VoiceProviderStackKind, VoiceProviderStackChoice<TProvider>>>;
17
+ };
18
+ export type VoiceProviderStackCapabilities<TProvider extends string = string> = Partial<Record<VoiceProviderStackKind, Partial<Record<TProvider, readonly string[]>>>>;
19
+ export type VoiceProviderStackCapabilityGap<TProvider extends string = string> = {
20
+ kind: VoiceProviderStackKind;
21
+ missing: string[];
22
+ present: string[];
23
+ provider?: TProvider;
24
+ required: string[];
25
+ status: 'fail' | 'pass' | 'warn';
26
+ };
27
+ export type VoiceProviderStackCapabilityGapReport<TProvider extends string = string> = {
28
+ gaps: VoiceProviderStackCapabilityGap<TProvider>[];
29
+ missing: number;
30
+ profile: VoiceReadinessProfileName;
31
+ status: 'fail' | 'pass' | 'warn';
32
+ };
33
+ export type VoiceProviderStackCapabilityGapInput<TProvider extends string = string> = VoiceProviderStackInput<TProvider> & {
34
+ capabilities?: VoiceProviderStackCapabilities<TProvider>;
35
+ recommendation?: VoiceProviderStackRecommendation<TProvider>;
36
+ required?: Partial<Record<VoiceProviderStackKind, readonly string[]>>;
37
+ };
38
+ export declare const recommendVoiceProviderStack: <TProvider extends string = string>(input: VoiceProviderStackInput<TProvider>) => VoiceProviderStackRecommendation<TProvider>;
39
+ export declare const evaluateVoiceProviderStackGaps: <TProvider extends string = string>(input: VoiceProviderStackCapabilityGapInput<TProvider>) => VoiceProviderStackCapabilityGapReport<TProvider>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.163",
3
+ "version": "0.0.22-beta.165",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",