@absolutejs/voice 0.0.22-beta.367 → 0.0.22-beta.368

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 CHANGED
@@ -1401,6 +1401,91 @@ assertVoiceProductionReadinessEvidence(readiness, {
1401
1401
  });
1402
1402
  ```
1403
1403
 
1404
+ Use `createVoiceProductionReadinessProofRuntime(...)` when the app needs a fresh, isolated proof window instead of letting stale local traces certify a deploy. The runtime is intentionally small: it owns a bounded in-memory trace store, route-cache defaults, a reusable TTL cache, a proof-freshness check, and optional synthetic provider/live-latency seed events. Your app still mounts routes, writes artifacts, and decides which proof sources matter.
1405
+
1406
+ ```ts
1407
+ import {
1408
+ createVoiceProductionReadinessProofRuntime,
1409
+ createVoiceProductionReadinessRoutes,
1410
+ createVoiceReadinessProfile
1411
+ } from '@absolutejs/voice';
1412
+
1413
+ const readinessProof = createVoiceProductionReadinessProofRuntime({
1414
+ cacheMs: 10_000,
1415
+ traceMaxAgeMs: 30 * 60_000
1416
+ });
1417
+
1418
+ const refreshReadinessProof = () =>
1419
+ readinessProof.refresh(async (metadata) => {
1420
+ await readinessProof.seedTraceProof({
1421
+ llmProvider: 'openai',
1422
+ scenarioId: 'provider-slo-proof',
1423
+ sttProvider: 'deepgram',
1424
+ ttsProvider: 'openai'
1425
+ });
1426
+
1427
+ await writeProofPack({
1428
+ generatedAt: metadata.generatedAt,
1429
+ runId: metadata.runId
1430
+ });
1431
+ });
1432
+
1433
+ app.use(
1434
+ createVoiceProductionReadinessRoutes({
1435
+ ...createVoiceReadinessProfile('phone-agent', {
1436
+ explain: true
1437
+ }),
1438
+ additionalChecks: async () => [
1439
+ await readinessProof.buildFreshnessCheck()
1440
+ ],
1441
+ cacheMs: readinessProof.options.cacheMs,
1442
+ providerSlo: async () => {
1443
+ await refreshReadinessProof();
1444
+ return {
1445
+ events: await readinessProof.store.list(),
1446
+ requiredKinds: ['llm', 'stt', 'tts']
1447
+ };
1448
+ },
1449
+ resolveOptions: async () => {
1450
+ await refreshReadinessProof();
1451
+ return {};
1452
+ },
1453
+ store: readinessProof.store,
1454
+ traceMaxAgeMs: readinessProof.options.traceMaxAgeMs
1455
+ })
1456
+ );
1457
+ ```
1458
+
1459
+ This primitive does not start workers, create persistent storage, mount a dashboard, or prescribe a deploy workflow. It only gives self-hosted apps one clean readiness-proof runtime so JSON, HTML, gate checks, proof packs, and trend artifacts agree on the same fresh evidence window.
1460
+
1461
+ Use `buildVoiceRealCallProfileEvidenceFromTraceEvents(...)` or `loadVoiceRealCallProfileEvidenceFromTraceStore(...)` when repeated real browser/phone sessions should drive profile defaults and provider/runtime recommendations. These helpers read ordinary trace events such as `session.error`, `provider.decision`, `client.live_latency`, `client.browser_media`, `client.telephony_media`, `client.barge_in`, and `turn_latency.stage`, then emit `VoiceProofTrendRealCallProfileEvidence[]` for `buildVoiceRealCallProfileHistoryReport(...)`.
1462
+
1463
+ ```ts
1464
+ import {
1465
+ buildVoiceRealCallProfileHistoryReport,
1466
+ createVoiceRealCallProfileHistoryRoutes,
1467
+ loadVoiceRealCallProfileEvidenceFromTraceStore
1468
+ } from '@absolutejs/voice';
1469
+
1470
+ const buildRealCallHistory = async () =>
1471
+ buildVoiceRealCallProfileHistoryReport({
1472
+ evidence: await loadVoiceRealCallProfileEvidenceFromTraceStore({
1473
+ defaultProfileId: 'meeting-recorder',
1474
+ defaultProfileLabel: 'Meeting recorder',
1475
+ store: runtime.traces
1476
+ }),
1477
+ source: 'runtime.traces'
1478
+ });
1479
+
1480
+ app.use(
1481
+ createVoiceRealCallProfileHistoryRoutes({
1482
+ source: buildRealCallHistory
1483
+ })
1484
+ );
1485
+ ```
1486
+
1487
+ The point is not to benchmark a fake demo once. The point is to let every real call add profile evidence so `/api/voice/real-call-profile-history`, provider recommendations, profile-switch readiness, and operations records can explain which provider/runtime path is winning for each call shape.
1488
+
1404
1489
  Built-in profiles:
1405
1490
 
1406
1491
  - `meeting-recorder`: live latency, session health, provider fallback, routing contracts, reconnect proof, and barge-in interruption proof.
@@ -4016,6 +4016,20 @@ var maxNumber = (values) => {
4016
4016
  const finite = values.filter((value) => typeof value === "number" && Number.isFinite(value));
4017
4017
  return finite.length > 0 ? Math.max(...finite) : undefined;
4018
4018
  };
4019
+ var percentile = (values, rank) => {
4020
+ const finite = values.filter((value) => Number.isFinite(value)).sort((left, right) => left - right);
4021
+ if (finite.length === 0) {
4022
+ return;
4023
+ }
4024
+ const index = Math.min(finite.length - 1, Math.max(0, Math.ceil(rank / 100 * finite.length) - 1));
4025
+ return finite[index];
4026
+ };
4027
+ var averageNumber = (values) => {
4028
+ const finite = values.filter((value) => Number.isFinite(value));
4029
+ return finite.length === 0 ? undefined : Math.round(finite.reduce((total, value) => total + value, 0) / finite.length);
4030
+ };
4031
+ var readString = (value) => typeof value === "string" && value.trim() ? value : undefined;
4032
+ var readNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
4019
4033
  var readProofTrendMaxLiveP95 = (report) => report.summary.maxLiveP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.liveLatency?.p95Ms));
4020
4034
  var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms ?? maxNumber((report.summary.providers ?? []).map((provider) => provider.p95Ms)) ?? maxNumber(report.cycles.flatMap((cycle) => (cycle.providers ?? []).map((provider) => provider.p95Ms)));
4021
4035
  var readProofTrendMaxTurnP95 = (report) => report.summary.maxTurnP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.turnLatency?.p95Ms));
@@ -4079,6 +4093,149 @@ var aggregateProofTrendRuntimeChannel = (channels) => {
4079
4093
  status: channels.some((channel) => channel.status === "fail") ? "fail" : channels.some((channel) => channel.status === "warn") ? "warn" : channels.every((channel) => channel.status === "pass") ? "pass" : undefined
4080
4094
  };
4081
4095
  };
4096
+ var readTraceRecord = (event) => event.payload;
4097
+ var readTraceProfileId = (events, options) => {
4098
+ for (const event of events) {
4099
+ const payload = readTraceRecord(event);
4100
+ const profileId = readString(payload.profileId) ?? readString(event.metadata?.profileId) ?? readString(payload.benchmarkProfileId) ?? readString(event.metadata?.benchmarkProfileId);
4101
+ if (profileId) {
4102
+ return profileId;
4103
+ }
4104
+ }
4105
+ return options.defaultProfileId;
4106
+ };
4107
+ var readProviderTraceRole = (payload) => readString(payload.kind) ?? readString(payload.role) ?? readString(payload.surface) ?? "provider";
4108
+ var readProviderTraceLatency = (payload) => readNumber2(payload.elapsedMs) ?? readNumber2(payload.latencyMs) ?? readNumber2(payload.durationMs);
4109
+ var readProviderTraceId = (payload) => readString(payload.selectedProvider) ?? readString(payload.provider) ?? readString(payload.model) ?? readString(payload.adapter);
4110
+ var readTraceStatus = (payload) => readString(payload.providerStatus) ?? readString(payload.status);
4111
+ var isFailingTraceStatus = (status) => status === "error" || status === "fail" || status === "failed" || status === "timeout";
4112
+ var summarizeProviderTraceEvidence = (events, maxProviderP95Ms) => {
4113
+ const providerLatencies = new Map;
4114
+ const providerMeta = new Map;
4115
+ for (const event of events) {
4116
+ if (event.type !== "session.error" && event.type !== "provider.decision") {
4117
+ continue;
4118
+ }
4119
+ const payload = readTraceRecord(event);
4120
+ const provider = readProviderTraceId(payload);
4121
+ if (!provider) {
4122
+ continue;
4123
+ }
4124
+ const role = readProviderTraceRole(payload);
4125
+ const id = `${role}:${provider}`;
4126
+ const latency = readProviderTraceLatency(payload);
4127
+ if (latency !== undefined) {
4128
+ providerLatencies.set(id, [...providerLatencies.get(id) ?? [], latency]);
4129
+ }
4130
+ const existing = providerMeta.get(id);
4131
+ providerMeta.set(id, {
4132
+ failed: existing?.failed === true || isFailingTraceStatus(readTraceStatus(payload)),
4133
+ label: existing?.label ?? `${role.toUpperCase()} ${provider}`,
4134
+ role: existing?.role ?? role
4135
+ });
4136
+ }
4137
+ return [...providerMeta.entries()].map(([id, meta]) => {
4138
+ const latencies = providerLatencies.get(id) ?? [];
4139
+ const p95Ms = percentile(latencies, 95);
4140
+ return {
4141
+ averageMs: averageNumber(latencies),
4142
+ id,
4143
+ label: meta.label,
4144
+ p50Ms: percentile(latencies, 50),
4145
+ p95Ms,
4146
+ role: meta.role,
4147
+ samples: latencies.length,
4148
+ status: meta.failed || (p95Ms ?? 0) > (maxProviderP95Ms ?? Number.POSITIVE_INFINITY) ? "fail" : latencies.length > 0 ? "pass" : "warn"
4149
+ };
4150
+ });
4151
+ };
4152
+ var summarizeTurnTraceP95 = (events) => {
4153
+ const explicit = events.filter((event) => event.type === "turn_latency.stage").map((event) => {
4154
+ const payload = readTraceRecord(event);
4155
+ return readNumber2(payload.totalMs) ?? readNumber2(payload.elapsedMs) ?? readNumber2(payload.latencyMs);
4156
+ }).filter((value) => value !== undefined);
4157
+ if (explicit.length > 0) {
4158
+ return percentile(explicit, 95);
4159
+ }
4160
+ const turnStages = new Map;
4161
+ for (const event of events) {
4162
+ if (event.type !== "turn_latency.stage" || !event.turnId) {
4163
+ continue;
4164
+ }
4165
+ const key = `${event.sessionId}:${event.turnId}`;
4166
+ turnStages.set(key, [...turnStages.get(key) ?? [], event.at]);
4167
+ }
4168
+ const totals = [...turnStages.values()].map((stages) => stages.length < 2 ? undefined : Math.max(...stages) - Math.min(...stages)).filter((value) => value !== undefined);
4169
+ return percentile(totals, 95);
4170
+ };
4171
+ var summarizeRuntimeChannelTraceEvidence = (events) => {
4172
+ const runtimeEvents = events.filter((event) => event.type === "client.browser_media" || event.type === "client.telephony_media" || event.type === "client.barge_in");
4173
+ if (runtimeEvents.length === 0) {
4174
+ return;
4175
+ }
4176
+ const firstAudio = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).firstAudioLatencyMs)).filter((value) => value !== undefined);
4177
+ const jitter = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).jitterMs)).filter((value) => value !== undefined);
4178
+ const timestampDrift = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).timestampDriftMs)).filter((value) => value !== undefined);
4179
+ const backpressure = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).backpressureEvents)).filter((value) => value !== undefined);
4180
+ const interruptions = runtimeEvents.map((event) => {
4181
+ const payload = readTraceRecord(event);
4182
+ return readNumber2(payload.interruptionLatencyMs) ?? readNumber2(payload.interruptionMs) ?? readNumber2(payload.elapsedMs);
4183
+ }).filter((value) => value !== undefined);
4184
+ return {
4185
+ maxBackpressureEvents: maxNumber(backpressure),
4186
+ maxFirstAudioLatencyMs: maxNumber(firstAudio),
4187
+ maxInterruptionP95Ms: percentile(interruptions, 95),
4188
+ maxJitterMs: maxNumber(jitter),
4189
+ maxTimestampDriftMs: maxNumber(timestampDrift),
4190
+ samples: runtimeEvents.length,
4191
+ status: runtimeEvents.some((event) => isFailingTraceStatus(readTraceStatus(readTraceRecord(event)))) ? "fail" : "pass"
4192
+ };
4193
+ };
4194
+ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) => {
4195
+ const sessionFilter = new Set(options.sessionIds ?? []);
4196
+ const eventsBySession = new Map;
4197
+ for (const event of events) {
4198
+ if (sessionFilter.size > 0 && !sessionFilter.has(event.sessionId)) {
4199
+ continue;
4200
+ }
4201
+ eventsBySession.set(event.sessionId, [
4202
+ ...eventsBySession.get(event.sessionId) ?? [],
4203
+ event
4204
+ ]);
4205
+ }
4206
+ return [...eventsBySession.entries()].map(([
4207
+ sessionId,
4208
+ sessionEvents
4209
+ ]) => {
4210
+ const profileId = readTraceProfileId(sessionEvents, options);
4211
+ if (!profileId) {
4212
+ return;
4213
+ }
4214
+ const providers = summarizeProviderTraceEvidence(sessionEvents, options.maxProviderP95Ms);
4215
+ const liveLatencies = sessionEvents.filter((event) => event.type === "client.live_latency").map((event) => {
4216
+ const payload = readTraceRecord(event);
4217
+ return readNumber2(payload.latencyMs) ?? readNumber2(payload.elapsedMs);
4218
+ }).filter((value) => value !== undefined);
4219
+ const turnP95Ms = summarizeTurnTraceP95(sessionEvents);
4220
+ const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
4221
+ const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
4222
+ return {
4223
+ generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
4224
+ liveP95Ms: percentile(liveLatencies, 95),
4225
+ ok: providers.every((provider) => provider.status !== "fail") && (runtimeChannel?.status ?? "pass") !== "fail",
4226
+ operationsRecordHref: `/voice-operations/${sessionId}`,
4227
+ profileDescription: options.profileDescriptions?.[profileId],
4228
+ profileId,
4229
+ profileLabel: options.profileLabels?.[profileId] ?? (profileId === options.defaultProfileId ? options.defaultProfileLabel : undefined),
4230
+ providerP95Ms,
4231
+ providers,
4232
+ runtimeChannel,
4233
+ sessionId,
4234
+ turnP95Ms
4235
+ };
4236
+ }).filter((evidence) => evidence !== undefined);
4237
+ };
4238
+ var loadVoiceRealCallProfileEvidenceFromTraceStore = async (options) => buildVoiceRealCallProfileEvidenceFromTraceEvents(await options.store.list({ limit: options.limit ?? 5000 }), options);
4082
4239
  var readProofTrendProviders = (reports) => aggregateProofTrendProviders(reports.flatMap((report) => report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : report.cycles.flatMap((cycle) => cycle.providers ?? [])));
4083
4240
  var exceedsProofTrendBudget = (value, budget) => value !== undefined && (!Number.isFinite(value) || value > budget);
4084
4241
  var readProofTrendProfileStatus = (profile, budgets) => {
package/dist/index.d.ts CHANGED
@@ -30,12 +30,12 @@ export { assertVoicePlatformCoverage, buildVoicePlatformCoverageSummary, createV
30
30
  export { assertVoiceCompetitiveCoverage, buildVoiceCompetitiveCoverageReport, createVoiceCompetitiveCoverageRoutes, evaluateVoiceCompetitiveCoverage, renderVoiceCompetitiveCoverageHTML, renderVoiceCompetitiveCoverageMarkdown } from './competitiveCoverage';
31
31
  export type { VoiceCompetitiveCoverageAssertionInput, VoiceCompetitiveCoverageAssertionReport, VoiceCompetitiveCoverageIssue, VoiceCompetitiveCoverageLevel, VoiceCompetitiveCoverageReport, VoiceCompetitiveCoverageReportInput, VoiceCompetitiveCoverageRoutesOptions, VoiceCompetitiveCoverageStatus, VoiceCompetitiveCoverageSummary, VoiceCompetitiveDepthLevel, VoiceCompetitiveEvidence, VoiceCompetitiveSurface } from './competitiveCoverage';
32
32
  export type { VoicePlatformCoverageAssertionInput, VoicePlatformCoverageAssertionReport, VoicePlatformCoverageEvidence, VoicePlatformCoverageRoutesOptions, VoicePlatformCoverageStatus, VoicePlatformCoverageSummary, VoicePlatformCoverageSummaryInput, VoicePlatformCoverageSurface } from './platformCoverage';
33
- export { assertVoiceProofTrendEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendProfileSummaries, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReportFromRealCallProfiles, buildVoiceProofTrendReport, buildVoiceRealCallProfileDefaults, buildVoiceRealCallProfileHistoryReport, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, createVoiceRealCallProfileHistoryRoutes, DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown, renderVoiceRealCallProfileHistoryHTML, renderVoiceRealCallProfileHistoryMarkdown, resolveVoiceRealCallProfileProviderRoute } from './proofTrends';
33
+ export { assertVoiceProofTrendEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendProfileSummaries, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReportFromRealCallProfiles, buildVoiceProofTrendReport, buildVoiceRealCallProfileEvidenceFromTraceEvents, buildVoiceRealCallProfileDefaults, buildVoiceRealCallProfileHistoryReport, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, createVoiceRealCallProfileHistoryRoutes, DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, loadVoiceRealCallProfileEvidenceFromTraceStore, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown, renderVoiceRealCallProfileHistoryHTML, renderVoiceRealCallProfileHistoryMarkdown, resolveVoiceRealCallProfileProviderRoute } from './proofTrends';
34
34
  export { applyVoiceProfileSwitchGuard, buildVoiceProfileSwitchReadinessReport, buildVoiceProfileSwitchLiveDecisionReport, createVoiceProfileSwitchLiveDecisionRoutes, createVoiceProfileSwitchPolicyProofRoutes, createVoiceProfileSwitchReadinessRoutes, recommendVoiceProfileSwitch, renderVoiceProfileSwitchLiveDecisionHTML, renderVoiceProfileSwitchPolicyProofHTML, renderVoiceProfileSwitchReadinessHTML, runVoiceProfileSwitchPolicyProof } from './profileSwitchRecommendation';
35
35
  export type { VoiceProfileSwitchGuardAction, VoiceProfileSwitchGuardDecision, VoiceProfileSwitchGuardMode, VoiceProfileSwitchGuardOptions, VoiceProfileSwitchObservedSignals, VoiceProfileSwitchLiveDecisionEvidence, VoiceProfileSwitchLiveDecisionReport, VoiceProfileSwitchLiveDecisionReportOptions, VoiceProfileSwitchLiveDecisionRoutesOptions, VoiceProfileSwitchLiveDecisionSession, VoiceProfileSwitchPolicyProofCase, VoiceProfileSwitchPolicyProofCaseResult, VoiceProfileSwitchPolicyProofOptions, VoiceProfileSwitchPolicyProofReport, VoiceProfileSwitchPolicyProofRoutesOptions, VoiceProfileSwitchReadinessIssue, VoiceProfileSwitchReadinessOptions, VoiceProfileSwitchReadinessReport, VoiceProfileSwitchReadinessRoutesOptions, VoiceProfileSwitchReadinessStatus, VoiceProfileSwitchRecommendation, VoiceProfileSwitchRecommendationOptions } from './profileSwitchRecommendation';
36
36
  export { buildVoiceProviderDecisionTraceReport, createVoiceProviderDecisionTraceEvent, createVoiceProviderDecisionTraceRoutes, listVoiceProviderDecisionTraces, renderVoiceProviderDecisionTraceHTML, renderVoiceProviderDecisionTraceMarkdown } from './providerDecisionTraces';
37
37
  export type { VoiceProviderDecisionStatus, VoiceProviderDecisionSurfaceReport, VoiceProviderDecisionTrace, VoiceProviderDecisionTraceInput, VoiceProviderDecisionTraceIssue, VoiceProviderDecisionTraceReport, VoiceProviderDecisionTraceReportOptions, VoiceProviderDecisionTraceRoutesOptions } from './providerDecisionTraces';
38
- export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendProfileDefinition, VoiceProofTrendProfileRecommendation, VoiceProofTrendProfileSummaryOptions, VoiceProofTrendProfileSummary, VoiceProofTrendProviderRecommendation, VoiceProofTrendProviderSummary, VoiceProofTrendRecommendation, VoiceProofTrendRecommendationOptions, VoiceProofTrendRecommendationReport, VoiceProofTrendRecommendationRoutesOptions, VoiceProofTrendRecommendationStatus, VoiceProofTrendRecommendationSurface, VoiceProofTrendRealCallProfileEvidence, VoiceProofTrendRealCallProfileReportOptions, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendRuntimeChannelSummary, VoiceProofTrendStatus, VoiceProofTrendSummary, VoiceRealCallProfileDefault, VoiceRealCallProfileDefaultsOptions, VoiceRealCallProfileDefaultsReport, VoiceRealCallProfileHistoryOptions, VoiceRealCallProfileHistoryReport, VoiceRealCallProfileHistoryRoutesOptions, VoiceRealCallProfileProviderRouteOptions } from './proofTrends';
38
+ export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendProfileDefinition, VoiceProofTrendProfileRecommendation, VoiceProofTrendProfileSummaryOptions, VoiceProofTrendProfileSummary, VoiceProofTrendProviderRecommendation, VoiceProofTrendProviderSummary, VoiceProofTrendRecommendation, VoiceProofTrendRecommendationOptions, VoiceProofTrendRecommendationReport, VoiceProofTrendRecommendationRoutesOptions, VoiceProofTrendRecommendationStatus, VoiceProofTrendRecommendationSurface, VoiceProofTrendRealCallProfileEvidence, VoiceProofTrendRealCallProfileReportOptions, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendRuntimeChannelSummary, VoiceProofTrendStatus, VoiceProofTrendSummary, VoiceRealCallProfileDefault, VoiceRealCallProfileDefaultsOptions, VoiceRealCallProfileDefaultsReport, VoiceRealCallProfileHistoryOptions, VoiceRealCallProfileHistoryReport, VoiceRealCallProfileHistoryRoutesOptions, VoiceRealCallProfileProviderRouteOptions, VoiceRealCallProfileTraceEvidenceOptions, VoiceRealCallProfileTraceStoreEvidenceOptions } from './proofTrends';
39
39
  export { assertVoiceSloCalibration, buildVoiceSloCalibrationReport, buildVoiceSloReadinessThresholdReport, createVoiceSloReadinessThresholdOptions, createVoiceSloReadinessThresholdRoutes, createVoiceSloThresholdProfile, createVoiceSloCalibrationRoutes, renderVoiceSloCalibrationMarkdown, renderVoiceSloReadinessThresholdHTML, renderVoiceSloReadinessThresholdMarkdown } from './sloCalibration';
40
40
  export type { VoiceSloCalibrationMetricKey, VoiceSloCalibrationOptions, VoiceSloCalibrationReport, VoiceSloCalibrationRoutesOptions, VoiceSloCalibrationSample, VoiceSloCalibrationStatus, VoiceSloCalibrationThreshold, VoiceSloCalibrationThresholds, VoiceSloReadinessThresholdReport, VoiceSloReadinessThresholdReportOptions, VoiceSloReadinessThresholdOptions, VoiceSloReadinessThresholdRoutesOptions, VoiceSloThresholdProfile } from './sloCalibration';
41
41
  export { assertVoiceLiveOpsControlEvidence, assertVoiceLiveOpsEvidence, buildVoiceLiveOpsControlState, createVoiceLiveOpsController, createVoiceLiveOpsRoutes, createVoiceMemoryLiveOpsControlStore, evaluateVoiceLiveOpsControlEvidence, evaluateVoiceLiveOpsEvidence, getVoiceLiveOpsControlStatus, VOICE_LIVE_OPS_ACTIONS } from './liveOps';
package/dist/index.js CHANGED
@@ -15445,6 +15445,20 @@ var maxNumber = (values) => {
15445
15445
  const finite = values.filter((value) => typeof value === "number" && Number.isFinite(value));
15446
15446
  return finite.length > 0 ? Math.max(...finite) : undefined;
15447
15447
  };
15448
+ var percentile2 = (values, rank) => {
15449
+ const finite = values.filter((value) => Number.isFinite(value)).sort((left, right) => left - right);
15450
+ if (finite.length === 0) {
15451
+ return;
15452
+ }
15453
+ const index = Math.min(finite.length - 1, Math.max(0, Math.ceil(rank / 100 * finite.length) - 1));
15454
+ return finite[index];
15455
+ };
15456
+ var averageNumber = (values) => {
15457
+ const finite = values.filter((value) => Number.isFinite(value));
15458
+ return finite.length === 0 ? undefined : Math.round(finite.reduce((total, value) => total + value, 0) / finite.length);
15459
+ };
15460
+ var readString2 = (value) => typeof value === "string" && value.trim() ? value : undefined;
15461
+ var readNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
15448
15462
  var readProofTrendMaxLiveP95 = (report) => report.summary.maxLiveP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.liveLatency?.p95Ms));
15449
15463
  var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms ?? maxNumber((report.summary.providers ?? []).map((provider) => provider.p95Ms)) ?? maxNumber(report.cycles.flatMap((cycle) => (cycle.providers ?? []).map((provider) => provider.p95Ms)));
15450
15464
  var readProofTrendMaxTurnP95 = (report) => report.summary.maxTurnP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.turnLatency?.p95Ms));
@@ -15508,6 +15522,149 @@ var aggregateProofTrendRuntimeChannel = (channels) => {
15508
15522
  status: channels.some((channel) => channel.status === "fail") ? "fail" : channels.some((channel) => channel.status === "warn") ? "warn" : channels.every((channel) => channel.status === "pass") ? "pass" : undefined
15509
15523
  };
15510
15524
  };
15525
+ var readTraceRecord = (event) => event.payload;
15526
+ var readTraceProfileId = (events, options) => {
15527
+ for (const event of events) {
15528
+ const payload = readTraceRecord(event);
15529
+ const profileId = readString2(payload.profileId) ?? readString2(event.metadata?.profileId) ?? readString2(payload.benchmarkProfileId) ?? readString2(event.metadata?.benchmarkProfileId);
15530
+ if (profileId) {
15531
+ return profileId;
15532
+ }
15533
+ }
15534
+ return options.defaultProfileId;
15535
+ };
15536
+ var readProviderTraceRole = (payload) => readString2(payload.kind) ?? readString2(payload.role) ?? readString2(payload.surface) ?? "provider";
15537
+ var readProviderTraceLatency = (payload) => readNumber2(payload.elapsedMs) ?? readNumber2(payload.latencyMs) ?? readNumber2(payload.durationMs);
15538
+ var readProviderTraceId = (payload) => readString2(payload.selectedProvider) ?? readString2(payload.provider) ?? readString2(payload.model) ?? readString2(payload.adapter);
15539
+ var readTraceStatus = (payload) => readString2(payload.providerStatus) ?? readString2(payload.status);
15540
+ var isFailingTraceStatus = (status) => status === "error" || status === "fail" || status === "failed" || status === "timeout";
15541
+ var summarizeProviderTraceEvidence = (events, maxProviderP95Ms) => {
15542
+ const providerLatencies = new Map;
15543
+ const providerMeta = new Map;
15544
+ for (const event of events) {
15545
+ if (event.type !== "session.error" && event.type !== "provider.decision") {
15546
+ continue;
15547
+ }
15548
+ const payload = readTraceRecord(event);
15549
+ const provider = readProviderTraceId(payload);
15550
+ if (!provider) {
15551
+ continue;
15552
+ }
15553
+ const role = readProviderTraceRole(payload);
15554
+ const id = `${role}:${provider}`;
15555
+ const latency = readProviderTraceLatency(payload);
15556
+ if (latency !== undefined) {
15557
+ providerLatencies.set(id, [...providerLatencies.get(id) ?? [], latency]);
15558
+ }
15559
+ const existing = providerMeta.get(id);
15560
+ providerMeta.set(id, {
15561
+ failed: existing?.failed === true || isFailingTraceStatus(readTraceStatus(payload)),
15562
+ label: existing?.label ?? `${role.toUpperCase()} ${provider}`,
15563
+ role: existing?.role ?? role
15564
+ });
15565
+ }
15566
+ return [...providerMeta.entries()].map(([id, meta]) => {
15567
+ const latencies = providerLatencies.get(id) ?? [];
15568
+ const p95Ms = percentile2(latencies, 95);
15569
+ return {
15570
+ averageMs: averageNumber(latencies),
15571
+ id,
15572
+ label: meta.label,
15573
+ p50Ms: percentile2(latencies, 50),
15574
+ p95Ms,
15575
+ role: meta.role,
15576
+ samples: latencies.length,
15577
+ status: meta.failed || (p95Ms ?? 0) > (maxProviderP95Ms ?? Number.POSITIVE_INFINITY) ? "fail" : latencies.length > 0 ? "pass" : "warn"
15578
+ };
15579
+ });
15580
+ };
15581
+ var summarizeTurnTraceP95 = (events) => {
15582
+ const explicit = events.filter((event) => event.type === "turn_latency.stage").map((event) => {
15583
+ const payload = readTraceRecord(event);
15584
+ return readNumber2(payload.totalMs) ?? readNumber2(payload.elapsedMs) ?? readNumber2(payload.latencyMs);
15585
+ }).filter((value) => value !== undefined);
15586
+ if (explicit.length > 0) {
15587
+ return percentile2(explicit, 95);
15588
+ }
15589
+ const turnStages = new Map;
15590
+ for (const event of events) {
15591
+ if (event.type !== "turn_latency.stage" || !event.turnId) {
15592
+ continue;
15593
+ }
15594
+ const key = `${event.sessionId}:${event.turnId}`;
15595
+ turnStages.set(key, [...turnStages.get(key) ?? [], event.at]);
15596
+ }
15597
+ const totals = [...turnStages.values()].map((stages) => stages.length < 2 ? undefined : Math.max(...stages) - Math.min(...stages)).filter((value) => value !== undefined);
15598
+ return percentile2(totals, 95);
15599
+ };
15600
+ var summarizeRuntimeChannelTraceEvidence = (events) => {
15601
+ const runtimeEvents = events.filter((event) => event.type === "client.browser_media" || event.type === "client.telephony_media" || event.type === "client.barge_in");
15602
+ if (runtimeEvents.length === 0) {
15603
+ return;
15604
+ }
15605
+ const firstAudio = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).firstAudioLatencyMs)).filter((value) => value !== undefined);
15606
+ const jitter = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).jitterMs)).filter((value) => value !== undefined);
15607
+ const timestampDrift = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).timestampDriftMs)).filter((value) => value !== undefined);
15608
+ const backpressure = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).backpressureEvents)).filter((value) => value !== undefined);
15609
+ const interruptions = runtimeEvents.map((event) => {
15610
+ const payload = readTraceRecord(event);
15611
+ return readNumber2(payload.interruptionLatencyMs) ?? readNumber2(payload.interruptionMs) ?? readNumber2(payload.elapsedMs);
15612
+ }).filter((value) => value !== undefined);
15613
+ return {
15614
+ maxBackpressureEvents: maxNumber(backpressure),
15615
+ maxFirstAudioLatencyMs: maxNumber(firstAudio),
15616
+ maxInterruptionP95Ms: percentile2(interruptions, 95),
15617
+ maxJitterMs: maxNumber(jitter),
15618
+ maxTimestampDriftMs: maxNumber(timestampDrift),
15619
+ samples: runtimeEvents.length,
15620
+ status: runtimeEvents.some((event) => isFailingTraceStatus(readTraceStatus(readTraceRecord(event)))) ? "fail" : "pass"
15621
+ };
15622
+ };
15623
+ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) => {
15624
+ const sessionFilter = new Set(options.sessionIds ?? []);
15625
+ const eventsBySession = new Map;
15626
+ for (const event of events) {
15627
+ if (sessionFilter.size > 0 && !sessionFilter.has(event.sessionId)) {
15628
+ continue;
15629
+ }
15630
+ eventsBySession.set(event.sessionId, [
15631
+ ...eventsBySession.get(event.sessionId) ?? [],
15632
+ event
15633
+ ]);
15634
+ }
15635
+ return [...eventsBySession.entries()].map(([
15636
+ sessionId,
15637
+ sessionEvents
15638
+ ]) => {
15639
+ const profileId = readTraceProfileId(sessionEvents, options);
15640
+ if (!profileId) {
15641
+ return;
15642
+ }
15643
+ const providers = summarizeProviderTraceEvidence(sessionEvents, options.maxProviderP95Ms);
15644
+ const liveLatencies = sessionEvents.filter((event) => event.type === "client.live_latency").map((event) => {
15645
+ const payload = readTraceRecord(event);
15646
+ return readNumber2(payload.latencyMs) ?? readNumber2(payload.elapsedMs);
15647
+ }).filter((value) => value !== undefined);
15648
+ const turnP95Ms = summarizeTurnTraceP95(sessionEvents);
15649
+ const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
15650
+ const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
15651
+ return {
15652
+ generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
15653
+ liveP95Ms: percentile2(liveLatencies, 95),
15654
+ ok: providers.every((provider) => provider.status !== "fail") && (runtimeChannel?.status ?? "pass") !== "fail",
15655
+ operationsRecordHref: `/voice-operations/${sessionId}`,
15656
+ profileDescription: options.profileDescriptions?.[profileId],
15657
+ profileId,
15658
+ profileLabel: options.profileLabels?.[profileId] ?? (profileId === options.defaultProfileId ? options.defaultProfileLabel : undefined),
15659
+ providerP95Ms,
15660
+ providers,
15661
+ runtimeChannel,
15662
+ sessionId,
15663
+ turnP95Ms
15664
+ };
15665
+ }).filter((evidence) => evidence !== undefined);
15666
+ };
15667
+ var loadVoiceRealCallProfileEvidenceFromTraceStore = async (options) => buildVoiceRealCallProfileEvidenceFromTraceEvents(await options.store.list({ limit: options.limit ?? 5000 }), options);
15511
15668
  var readProofTrendProviders = (reports) => aggregateProofTrendProviders(reports.flatMap((report) => report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : report.cycles.flatMap((cycle) => cycle.providers ?? [])));
15512
15669
  var exceedsProofTrendBudget = (value, budget) => value !== undefined && (!Number.isFinite(value) || value > budget);
15513
15670
  var readProofTrendProfileStatus = (profile, budgets) => {
@@ -17189,7 +17346,7 @@ var DEFAULT_WARN_RATIO = 0.8;
17189
17346
  var DEFAULT_MIN_PASSING_RUNS = 3;
17190
17347
  var roundMs = (value) => Math.max(1, Math.ceil(value));
17191
17348
  var finiteNumber = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
17192
- var percentile2 = (values, rank) => {
17349
+ var percentile3 = (values, rank) => {
17193
17350
  if (values.length === 0) {
17194
17351
  return;
17195
17352
  }
@@ -17213,7 +17370,7 @@ var normalizeSample = (input) => {
17213
17370
  return input;
17214
17371
  };
17215
17372
  var createThreshold = (metric, values, options) => {
17216
- const baselineP95Ms = percentile2(values, 95);
17373
+ const baselineP95Ms = percentile3(values, 95);
17217
17374
  const maxObservedMs = values.length > 0 ? Math.max(...values) : undefined;
17218
17375
  const recommendedMs = baselineP95Ms === undefined ? undefined : roundMs(Math.max(options.minimumMs, baselineP95Ms * options.headroomMultiplier));
17219
17376
  const warnAfterMs = recommendedMs === undefined ? undefined : roundMs(Math.max(options.minimumMs, recommendedMs * options.warnRatio));
@@ -21729,7 +21886,7 @@ var createVoiceTurnLatencyRoutes = (options) => {
21729
21886
  // src/liveLatency.ts
21730
21887
  import { Elysia as Elysia37 } from "elysia";
21731
21888
  var escapeHtml38 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21732
- var percentile3 = (values, percentileValue) => {
21889
+ var percentile4 = (values, percentileValue) => {
21733
21890
  if (values.length === 0) {
21734
21891
  return;
21735
21892
  }
@@ -21765,8 +21922,8 @@ var summarizeVoiceLiveLatency = async (options) => {
21765
21922
  averageLatencyMs: latencies.length > 0 ? Math.round(latencies.reduce((total, value) => total + value, 0) / latencies.length) : undefined,
21766
21923
  checkedAt: Date.now(),
21767
21924
  failed,
21768
- p50LatencyMs: percentile3(latencies, 50),
21769
- p95LatencyMs: percentile3(latencies, 95),
21925
+ p50LatencyMs: percentile4(latencies, 50),
21926
+ p95LatencyMs: percentile4(latencies, 95),
21770
21927
  recent,
21771
21928
  status: latencies.length === 0 ? "empty" : failed > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
21772
21929
  total: latencies.length,
@@ -21842,7 +21999,7 @@ var TRACE_TYPES = [
21842
21999
  ];
21843
22000
  var getNumber8 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
21844
22001
  var getString14 = (value) => typeof value === "string" && value.trim() ? value : undefined;
21845
- var percentile4 = (values, percentileValue) => {
22002
+ var percentile5 = (values, percentileValue) => {
21846
22003
  if (values.length === 0) {
21847
22004
  return;
21848
22005
  }
@@ -22050,8 +22207,8 @@ var summarizeStage = (stage, measurements, options) => {
22050
22207
  label: STAGE_LABELS[stage],
22051
22208
  maxMs: latencies.length > 0 ? Math.max(...latencies) : undefined,
22052
22209
  measurements: stageMeasurements,
22053
- p50Ms: percentile4(latencies, 50),
22054
- p95Ms: percentile4(latencies, 95),
22210
+ p50Ms: percentile5(latencies, 50),
22211
+ p95Ms: percentile5(latencies, 95),
22055
22212
  stage,
22056
22213
  status: stageMeasurements.length === 0 ? "empty" : failed > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
22057
22214
  total: stageMeasurements.length,
@@ -27869,7 +28026,7 @@ var rate3 = (count, total) => count / Math.max(1, total);
27869
28026
  var uniqueSorted7 = (values) => [
27870
28027
  ...new Set(values.filter((value) => typeof value === "string"))
27871
28028
  ].sort();
27872
- var percentile5 = (values, rank) => {
28029
+ var percentile6 = (values, rank) => {
27873
28030
  if (values.length === 0) {
27874
28031
  return 0;
27875
28032
  }
@@ -27927,7 +28084,7 @@ var summarizeKind = (kind, events, thresholds, required) => {
27927
28084
  unit: "rate"
27928
28085
  }),
27929
28086
  p95ElapsedMs: createMetric2({
27930
- actual: percentile5(latencies, 95),
28087
+ actual: percentile6(latencies, 95),
27931
28088
  label: "P95 latency",
27932
28089
  threshold: thresholds.maxP95ElapsedMs,
27933
28090
  unit: "ms"
@@ -38256,6 +38413,7 @@ export {
38256
38413
  muteVoiceMonitorIssue,
38257
38414
  matchesVoiceOpsTaskAssignmentRule,
38258
38415
  markVoiceOpsTaskSLABreached,
38416
+ loadVoiceRealCallProfileEvidenceFromTraceStore,
38259
38417
  loadVoiceObservabilityExportReplaySource,
38260
38418
  listVoiceRoutingEvents,
38261
38419
  listVoiceProviderDecisionTraces,
@@ -38634,6 +38792,7 @@ export {
38634
38792
  buildVoiceRealtimeChannelRuntimeSamplesFromTrace,
38635
38793
  buildVoiceRealtimeChannelReport,
38636
38794
  buildVoiceRealCallProfileHistoryReport,
38795
+ buildVoiceRealCallProfileEvidenceFromTraceEvents,
38637
38796
  buildVoiceRealCallProfileDefaults,
38638
38797
  buildVoiceProviderSloReport,
38639
38798
  buildVoiceProviderOrchestrationReport,
@@ -1,4 +1,5 @@
1
1
  import { Elysia } from 'elysia';
2
+ import type { StoredVoiceTraceEvent, VoiceTraceEventStore } from './trace';
2
3
  export type VoiceProofTrendStatus = 'empty' | 'fail' | 'pass' | 'stale';
3
4
  export type VoiceProofTrendSummary = {
4
5
  cycles?: number;
@@ -134,6 +135,18 @@ export type VoiceProofTrendRealCallProfileEvidence = {
134
135
  sessionId: string;
135
136
  turnP95Ms?: number;
136
137
  };
138
+ export type VoiceRealCallProfileTraceEvidenceOptions = {
139
+ defaultProfileId?: string;
140
+ defaultProfileLabel?: string;
141
+ maxProviderP95Ms?: number;
142
+ profileDescriptions?: Record<string, string>;
143
+ profileLabels?: Record<string, string>;
144
+ sessionIds?: readonly string[];
145
+ };
146
+ export type VoiceRealCallProfileTraceStoreEvidenceOptions = VoiceRealCallProfileTraceEvidenceOptions & {
147
+ limit?: number;
148
+ store: VoiceTraceEventStore;
149
+ };
137
150
  export type VoiceProofTrendRealCallProfileReportOptions = VoiceProofTrendProfileSummaryOptions & {
138
151
  baseUrl?: string;
139
152
  evidence: readonly VoiceProofTrendRealCallProfileEvidence[];
@@ -370,6 +383,8 @@ export declare const normalizeVoiceProofTrendReport: (value: VoiceProofTrendRepo
370
383
  export declare const readVoiceProofTrendReportFile: (path: string, options?: {
371
384
  maxAgeMs?: number;
372
385
  }) => Promise<VoiceProofTrendReport>;
386
+ export declare const buildVoiceRealCallProfileEvidenceFromTraceEvents: (events: readonly StoredVoiceTraceEvent[], options?: VoiceRealCallProfileTraceEvidenceOptions) => VoiceProofTrendRealCallProfileEvidence[];
387
+ export declare const loadVoiceRealCallProfileEvidenceFromTraceStore: (options: VoiceRealCallProfileTraceStoreEvidenceOptions) => Promise<VoiceProofTrendRealCallProfileEvidence[]>;
373
388
  export declare const buildVoiceProofTrendProfileSummaries: (input: VoiceProofTrendReport | readonly VoiceProofTrendReport[], options?: VoiceProofTrendProfileSummaryOptions) => VoiceProofTrendProfileSummary[];
374
389
  export declare const buildVoiceProofTrendReportFromRealCallProfiles: (options: VoiceProofTrendRealCallProfileReportOptions) => VoiceProofTrendReport;
375
390
  export declare const buildVoiceRealCallProfileDefaults: (input: VoiceRealCallProfileHistoryReport | VoiceProofTrendReport, options?: VoiceRealCallProfileDefaultsOptions) => VoiceRealCallProfileDefaultsReport;
@@ -1603,6 +1603,20 @@ var maxNumber = (values) => {
1603
1603
  const finite = values.filter((value) => typeof value === "number" && Number.isFinite(value));
1604
1604
  return finite.length > 0 ? Math.max(...finite) : undefined;
1605
1605
  };
1606
+ var percentile = (values, rank) => {
1607
+ const finite = values.filter((value) => Number.isFinite(value)).sort((left, right) => left - right);
1608
+ if (finite.length === 0) {
1609
+ return;
1610
+ }
1611
+ const index = Math.min(finite.length - 1, Math.max(0, Math.ceil(rank / 100 * finite.length) - 1));
1612
+ return finite[index];
1613
+ };
1614
+ var averageNumber = (values) => {
1615
+ const finite = values.filter((value) => Number.isFinite(value));
1616
+ return finite.length === 0 ? undefined : Math.round(finite.reduce((total, value) => total + value, 0) / finite.length);
1617
+ };
1618
+ var readString = (value) => typeof value === "string" && value.trim() ? value : undefined;
1619
+ var readNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
1606
1620
  var readProofTrendMaxLiveP95 = (report) => report.summary.maxLiveP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.liveLatency?.p95Ms));
1607
1621
  var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms ?? maxNumber((report.summary.providers ?? []).map((provider) => provider.p95Ms)) ?? maxNumber(report.cycles.flatMap((cycle) => (cycle.providers ?? []).map((provider) => provider.p95Ms)));
1608
1622
  var readProofTrendMaxTurnP95 = (report) => report.summary.maxTurnP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.turnLatency?.p95Ms));
@@ -1666,6 +1680,149 @@ var aggregateProofTrendRuntimeChannel = (channels) => {
1666
1680
  status: channels.some((channel) => channel.status === "fail") ? "fail" : channels.some((channel) => channel.status === "warn") ? "warn" : channels.every((channel) => channel.status === "pass") ? "pass" : undefined
1667
1681
  };
1668
1682
  };
1683
+ var readTraceRecord = (event) => event.payload;
1684
+ var readTraceProfileId = (events, options) => {
1685
+ for (const event of events) {
1686
+ const payload = readTraceRecord(event);
1687
+ const profileId = readString(payload.profileId) ?? readString(event.metadata?.profileId) ?? readString(payload.benchmarkProfileId) ?? readString(event.metadata?.benchmarkProfileId);
1688
+ if (profileId) {
1689
+ return profileId;
1690
+ }
1691
+ }
1692
+ return options.defaultProfileId;
1693
+ };
1694
+ var readProviderTraceRole = (payload) => readString(payload.kind) ?? readString(payload.role) ?? readString(payload.surface) ?? "provider";
1695
+ var readProviderTraceLatency = (payload) => readNumber2(payload.elapsedMs) ?? readNumber2(payload.latencyMs) ?? readNumber2(payload.durationMs);
1696
+ var readProviderTraceId = (payload) => readString(payload.selectedProvider) ?? readString(payload.provider) ?? readString(payload.model) ?? readString(payload.adapter);
1697
+ var readTraceStatus = (payload) => readString(payload.providerStatus) ?? readString(payload.status);
1698
+ var isFailingTraceStatus = (status) => status === "error" || status === "fail" || status === "failed" || status === "timeout";
1699
+ var summarizeProviderTraceEvidence = (events, maxProviderP95Ms) => {
1700
+ const providerLatencies = new Map;
1701
+ const providerMeta = new Map;
1702
+ for (const event of events) {
1703
+ if (event.type !== "session.error" && event.type !== "provider.decision") {
1704
+ continue;
1705
+ }
1706
+ const payload = readTraceRecord(event);
1707
+ const provider = readProviderTraceId(payload);
1708
+ if (!provider) {
1709
+ continue;
1710
+ }
1711
+ const role = readProviderTraceRole(payload);
1712
+ const id = `${role}:${provider}`;
1713
+ const latency = readProviderTraceLatency(payload);
1714
+ if (latency !== undefined) {
1715
+ providerLatencies.set(id, [...providerLatencies.get(id) ?? [], latency]);
1716
+ }
1717
+ const existing = providerMeta.get(id);
1718
+ providerMeta.set(id, {
1719
+ failed: existing?.failed === true || isFailingTraceStatus(readTraceStatus(payload)),
1720
+ label: existing?.label ?? `${role.toUpperCase()} ${provider}`,
1721
+ role: existing?.role ?? role
1722
+ });
1723
+ }
1724
+ return [...providerMeta.entries()].map(([id, meta]) => {
1725
+ const latencies = providerLatencies.get(id) ?? [];
1726
+ const p95Ms = percentile(latencies, 95);
1727
+ return {
1728
+ averageMs: averageNumber(latencies),
1729
+ id,
1730
+ label: meta.label,
1731
+ p50Ms: percentile(latencies, 50),
1732
+ p95Ms,
1733
+ role: meta.role,
1734
+ samples: latencies.length,
1735
+ status: meta.failed || (p95Ms ?? 0) > (maxProviderP95Ms ?? Number.POSITIVE_INFINITY) ? "fail" : latencies.length > 0 ? "pass" : "warn"
1736
+ };
1737
+ });
1738
+ };
1739
+ var summarizeTurnTraceP95 = (events) => {
1740
+ const explicit = events.filter((event) => event.type === "turn_latency.stage").map((event) => {
1741
+ const payload = readTraceRecord(event);
1742
+ return readNumber2(payload.totalMs) ?? readNumber2(payload.elapsedMs) ?? readNumber2(payload.latencyMs);
1743
+ }).filter((value) => value !== undefined);
1744
+ if (explicit.length > 0) {
1745
+ return percentile(explicit, 95);
1746
+ }
1747
+ const turnStages = new Map;
1748
+ for (const event of events) {
1749
+ if (event.type !== "turn_latency.stage" || !event.turnId) {
1750
+ continue;
1751
+ }
1752
+ const key = `${event.sessionId}:${event.turnId}`;
1753
+ turnStages.set(key, [...turnStages.get(key) ?? [], event.at]);
1754
+ }
1755
+ const totals = [...turnStages.values()].map((stages) => stages.length < 2 ? undefined : Math.max(...stages) - Math.min(...stages)).filter((value) => value !== undefined);
1756
+ return percentile(totals, 95);
1757
+ };
1758
+ var summarizeRuntimeChannelTraceEvidence = (events) => {
1759
+ const runtimeEvents = events.filter((event) => event.type === "client.browser_media" || event.type === "client.telephony_media" || event.type === "client.barge_in");
1760
+ if (runtimeEvents.length === 0) {
1761
+ return;
1762
+ }
1763
+ const firstAudio = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).firstAudioLatencyMs)).filter((value) => value !== undefined);
1764
+ const jitter = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).jitterMs)).filter((value) => value !== undefined);
1765
+ const timestampDrift = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).timestampDriftMs)).filter((value) => value !== undefined);
1766
+ const backpressure = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).backpressureEvents)).filter((value) => value !== undefined);
1767
+ const interruptions = runtimeEvents.map((event) => {
1768
+ const payload = readTraceRecord(event);
1769
+ return readNumber2(payload.interruptionLatencyMs) ?? readNumber2(payload.interruptionMs) ?? readNumber2(payload.elapsedMs);
1770
+ }).filter((value) => value !== undefined);
1771
+ return {
1772
+ maxBackpressureEvents: maxNumber(backpressure),
1773
+ maxFirstAudioLatencyMs: maxNumber(firstAudio),
1774
+ maxInterruptionP95Ms: percentile(interruptions, 95),
1775
+ maxJitterMs: maxNumber(jitter),
1776
+ maxTimestampDriftMs: maxNumber(timestampDrift),
1777
+ samples: runtimeEvents.length,
1778
+ status: runtimeEvents.some((event) => isFailingTraceStatus(readTraceStatus(readTraceRecord(event)))) ? "fail" : "pass"
1779
+ };
1780
+ };
1781
+ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) => {
1782
+ const sessionFilter = new Set(options.sessionIds ?? []);
1783
+ const eventsBySession = new Map;
1784
+ for (const event of events) {
1785
+ if (sessionFilter.size > 0 && !sessionFilter.has(event.sessionId)) {
1786
+ continue;
1787
+ }
1788
+ eventsBySession.set(event.sessionId, [
1789
+ ...eventsBySession.get(event.sessionId) ?? [],
1790
+ event
1791
+ ]);
1792
+ }
1793
+ return [...eventsBySession.entries()].map(([
1794
+ sessionId,
1795
+ sessionEvents
1796
+ ]) => {
1797
+ const profileId = readTraceProfileId(sessionEvents, options);
1798
+ if (!profileId) {
1799
+ return;
1800
+ }
1801
+ const providers = summarizeProviderTraceEvidence(sessionEvents, options.maxProviderP95Ms);
1802
+ const liveLatencies = sessionEvents.filter((event) => event.type === "client.live_latency").map((event) => {
1803
+ const payload = readTraceRecord(event);
1804
+ return readNumber2(payload.latencyMs) ?? readNumber2(payload.elapsedMs);
1805
+ }).filter((value) => value !== undefined);
1806
+ const turnP95Ms = summarizeTurnTraceP95(sessionEvents);
1807
+ const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
1808
+ const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
1809
+ return {
1810
+ generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
1811
+ liveP95Ms: percentile(liveLatencies, 95),
1812
+ ok: providers.every((provider) => provider.status !== "fail") && (runtimeChannel?.status ?? "pass") !== "fail",
1813
+ operationsRecordHref: `/voice-operations/${sessionId}`,
1814
+ profileDescription: options.profileDescriptions?.[profileId],
1815
+ profileId,
1816
+ profileLabel: options.profileLabels?.[profileId] ?? (profileId === options.defaultProfileId ? options.defaultProfileLabel : undefined),
1817
+ providerP95Ms,
1818
+ providers,
1819
+ runtimeChannel,
1820
+ sessionId,
1821
+ turnP95Ms
1822
+ };
1823
+ }).filter((evidence) => evidence !== undefined);
1824
+ };
1825
+ var loadVoiceRealCallProfileEvidenceFromTraceStore = async (options) => buildVoiceRealCallProfileEvidenceFromTraceEvents(await options.store.list({ limit: options.limit ?? 5000 }), options);
1669
1826
  var readProofTrendProviders = (reports) => aggregateProofTrendProviders(reports.flatMap((report) => report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : report.cycles.flatMap((cycle) => cycle.providers ?? [])));
1670
1827
  var exceedsProofTrendBudget = (value, budget) => value !== undefined && (!Number.isFinite(value) || value > budget);
1671
1828
  var readProofTrendProfileStatus = (profile, budgets) => {
package/dist/vue/index.js CHANGED
@@ -1524,6 +1524,20 @@ var maxNumber = (values) => {
1524
1524
  const finite = values.filter((value) => typeof value === "number" && Number.isFinite(value));
1525
1525
  return finite.length > 0 ? Math.max(...finite) : undefined;
1526
1526
  };
1527
+ var percentile = (values, rank) => {
1528
+ const finite = values.filter((value) => Number.isFinite(value)).sort((left, right) => left - right);
1529
+ if (finite.length === 0) {
1530
+ return;
1531
+ }
1532
+ const index = Math.min(finite.length - 1, Math.max(0, Math.ceil(rank / 100 * finite.length) - 1));
1533
+ return finite[index];
1534
+ };
1535
+ var averageNumber = (values) => {
1536
+ const finite = values.filter((value) => Number.isFinite(value));
1537
+ return finite.length === 0 ? undefined : Math.round(finite.reduce((total, value) => total + value, 0) / finite.length);
1538
+ };
1539
+ var readString = (value) => typeof value === "string" && value.trim() ? value : undefined;
1540
+ var readNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
1527
1541
  var readProofTrendMaxLiveP95 = (report) => report.summary.maxLiveP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.liveLatency?.p95Ms));
1528
1542
  var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms ?? maxNumber((report.summary.providers ?? []).map((provider) => provider.p95Ms)) ?? maxNumber(report.cycles.flatMap((cycle) => (cycle.providers ?? []).map((provider) => provider.p95Ms)));
1529
1543
  var readProofTrendMaxTurnP95 = (report) => report.summary.maxTurnP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.turnLatency?.p95Ms));
@@ -1587,6 +1601,149 @@ var aggregateProofTrendRuntimeChannel = (channels) => {
1587
1601
  status: channels.some((channel) => channel.status === "fail") ? "fail" : channels.some((channel) => channel.status === "warn") ? "warn" : channels.every((channel) => channel.status === "pass") ? "pass" : undefined
1588
1602
  };
1589
1603
  };
1604
+ var readTraceRecord = (event) => event.payload;
1605
+ var readTraceProfileId = (events, options) => {
1606
+ for (const event of events) {
1607
+ const payload = readTraceRecord(event);
1608
+ const profileId = readString(payload.profileId) ?? readString(event.metadata?.profileId) ?? readString(payload.benchmarkProfileId) ?? readString(event.metadata?.benchmarkProfileId);
1609
+ if (profileId) {
1610
+ return profileId;
1611
+ }
1612
+ }
1613
+ return options.defaultProfileId;
1614
+ };
1615
+ var readProviderTraceRole = (payload) => readString(payload.kind) ?? readString(payload.role) ?? readString(payload.surface) ?? "provider";
1616
+ var readProviderTraceLatency = (payload) => readNumber2(payload.elapsedMs) ?? readNumber2(payload.latencyMs) ?? readNumber2(payload.durationMs);
1617
+ var readProviderTraceId = (payload) => readString(payload.selectedProvider) ?? readString(payload.provider) ?? readString(payload.model) ?? readString(payload.adapter);
1618
+ var readTraceStatus = (payload) => readString(payload.providerStatus) ?? readString(payload.status);
1619
+ var isFailingTraceStatus = (status) => status === "error" || status === "fail" || status === "failed" || status === "timeout";
1620
+ var summarizeProviderTraceEvidence = (events, maxProviderP95Ms) => {
1621
+ const providerLatencies = new Map;
1622
+ const providerMeta = new Map;
1623
+ for (const event of events) {
1624
+ if (event.type !== "session.error" && event.type !== "provider.decision") {
1625
+ continue;
1626
+ }
1627
+ const payload = readTraceRecord(event);
1628
+ const provider = readProviderTraceId(payload);
1629
+ if (!provider) {
1630
+ continue;
1631
+ }
1632
+ const role = readProviderTraceRole(payload);
1633
+ const id = `${role}:${provider}`;
1634
+ const latency = readProviderTraceLatency(payload);
1635
+ if (latency !== undefined) {
1636
+ providerLatencies.set(id, [...providerLatencies.get(id) ?? [], latency]);
1637
+ }
1638
+ const existing = providerMeta.get(id);
1639
+ providerMeta.set(id, {
1640
+ failed: existing?.failed === true || isFailingTraceStatus(readTraceStatus(payload)),
1641
+ label: existing?.label ?? `${role.toUpperCase()} ${provider}`,
1642
+ role: existing?.role ?? role
1643
+ });
1644
+ }
1645
+ return [...providerMeta.entries()].map(([id, meta]) => {
1646
+ const latencies = providerLatencies.get(id) ?? [];
1647
+ const p95Ms = percentile(latencies, 95);
1648
+ return {
1649
+ averageMs: averageNumber(latencies),
1650
+ id,
1651
+ label: meta.label,
1652
+ p50Ms: percentile(latencies, 50),
1653
+ p95Ms,
1654
+ role: meta.role,
1655
+ samples: latencies.length,
1656
+ status: meta.failed || (p95Ms ?? 0) > (maxProviderP95Ms ?? Number.POSITIVE_INFINITY) ? "fail" : latencies.length > 0 ? "pass" : "warn"
1657
+ };
1658
+ });
1659
+ };
1660
+ var summarizeTurnTraceP95 = (events) => {
1661
+ const explicit = events.filter((event) => event.type === "turn_latency.stage").map((event) => {
1662
+ const payload = readTraceRecord(event);
1663
+ return readNumber2(payload.totalMs) ?? readNumber2(payload.elapsedMs) ?? readNumber2(payload.latencyMs);
1664
+ }).filter((value) => value !== undefined);
1665
+ if (explicit.length > 0) {
1666
+ return percentile(explicit, 95);
1667
+ }
1668
+ const turnStages = new Map;
1669
+ for (const event of events) {
1670
+ if (event.type !== "turn_latency.stage" || !event.turnId) {
1671
+ continue;
1672
+ }
1673
+ const key = `${event.sessionId}:${event.turnId}`;
1674
+ turnStages.set(key, [...turnStages.get(key) ?? [], event.at]);
1675
+ }
1676
+ const totals = [...turnStages.values()].map((stages) => stages.length < 2 ? undefined : Math.max(...stages) - Math.min(...stages)).filter((value) => value !== undefined);
1677
+ return percentile(totals, 95);
1678
+ };
1679
+ var summarizeRuntimeChannelTraceEvidence = (events) => {
1680
+ const runtimeEvents = events.filter((event) => event.type === "client.browser_media" || event.type === "client.telephony_media" || event.type === "client.barge_in");
1681
+ if (runtimeEvents.length === 0) {
1682
+ return;
1683
+ }
1684
+ const firstAudio = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).firstAudioLatencyMs)).filter((value) => value !== undefined);
1685
+ const jitter = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).jitterMs)).filter((value) => value !== undefined);
1686
+ const timestampDrift = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).timestampDriftMs)).filter((value) => value !== undefined);
1687
+ const backpressure = runtimeEvents.map((event) => readNumber2(readTraceRecord(event).backpressureEvents)).filter((value) => value !== undefined);
1688
+ const interruptions = runtimeEvents.map((event) => {
1689
+ const payload = readTraceRecord(event);
1690
+ return readNumber2(payload.interruptionLatencyMs) ?? readNumber2(payload.interruptionMs) ?? readNumber2(payload.elapsedMs);
1691
+ }).filter((value) => value !== undefined);
1692
+ return {
1693
+ maxBackpressureEvents: maxNumber(backpressure),
1694
+ maxFirstAudioLatencyMs: maxNumber(firstAudio),
1695
+ maxInterruptionP95Ms: percentile(interruptions, 95),
1696
+ maxJitterMs: maxNumber(jitter),
1697
+ maxTimestampDriftMs: maxNumber(timestampDrift),
1698
+ samples: runtimeEvents.length,
1699
+ status: runtimeEvents.some((event) => isFailingTraceStatus(readTraceStatus(readTraceRecord(event)))) ? "fail" : "pass"
1700
+ };
1701
+ };
1702
+ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) => {
1703
+ const sessionFilter = new Set(options.sessionIds ?? []);
1704
+ const eventsBySession = new Map;
1705
+ for (const event of events) {
1706
+ if (sessionFilter.size > 0 && !sessionFilter.has(event.sessionId)) {
1707
+ continue;
1708
+ }
1709
+ eventsBySession.set(event.sessionId, [
1710
+ ...eventsBySession.get(event.sessionId) ?? [],
1711
+ event
1712
+ ]);
1713
+ }
1714
+ return [...eventsBySession.entries()].map(([
1715
+ sessionId,
1716
+ sessionEvents
1717
+ ]) => {
1718
+ const profileId = readTraceProfileId(sessionEvents, options);
1719
+ if (!profileId) {
1720
+ return;
1721
+ }
1722
+ const providers = summarizeProviderTraceEvidence(sessionEvents, options.maxProviderP95Ms);
1723
+ const liveLatencies = sessionEvents.filter((event) => event.type === "client.live_latency").map((event) => {
1724
+ const payload = readTraceRecord(event);
1725
+ return readNumber2(payload.latencyMs) ?? readNumber2(payload.elapsedMs);
1726
+ }).filter((value) => value !== undefined);
1727
+ const turnP95Ms = summarizeTurnTraceP95(sessionEvents);
1728
+ const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
1729
+ const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
1730
+ return {
1731
+ generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
1732
+ liveP95Ms: percentile(liveLatencies, 95),
1733
+ ok: providers.every((provider) => provider.status !== "fail") && (runtimeChannel?.status ?? "pass") !== "fail",
1734
+ operationsRecordHref: `/voice-operations/${sessionId}`,
1735
+ profileDescription: options.profileDescriptions?.[profileId],
1736
+ profileId,
1737
+ profileLabel: options.profileLabels?.[profileId] ?? (profileId === options.defaultProfileId ? options.defaultProfileLabel : undefined),
1738
+ providerP95Ms,
1739
+ providers,
1740
+ runtimeChannel,
1741
+ sessionId,
1742
+ turnP95Ms
1743
+ };
1744
+ }).filter((evidence) => evidence !== undefined);
1745
+ };
1746
+ var loadVoiceRealCallProfileEvidenceFromTraceStore = async (options) => buildVoiceRealCallProfileEvidenceFromTraceEvents(await options.store.list({ limit: options.limit ?? 5000 }), options);
1590
1747
  var readProofTrendProviders = (reports) => aggregateProofTrendProviders(reports.flatMap((report) => report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : report.cycles.flatMap((cycle) => cycle.providers ?? [])));
1591
1748
  var exceedsProofTrendBudget = (value, budget) => value !== undefined && (!Number.isFinite(value) || value > budget);
1592
1749
  var readProofTrendProfileStatus = (profile, budgets) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.367",
3
+ "version": "0.0.22-beta.368",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",