@absolutejs/voice 0.0.22-beta.337 → 0.0.22-beta.339

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.
@@ -3747,6 +3747,40 @@ var defineVoicePlatformCoverageElement = (tagName = "absolute-voice-platform-cov
3747
3747
  // src/proofTrends.ts
3748
3748
  import { Elysia } from "elysia";
3749
3749
  var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
3750
+ var DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS = [
3751
+ {
3752
+ description: "Browser recorder with longer passive listening and transcript capture.",
3753
+ id: "meeting-recorder",
3754
+ label: "Meeting recorder"
3755
+ },
3756
+ {
3757
+ description: "Realtime support agent with fast interruption recovery and tool-ready turns.",
3758
+ id: "support-agent",
3759
+ label: "Support agent",
3760
+ liveOffsetMs: 17,
3761
+ providerOffsetMs: 20,
3762
+ runtimeOffsetMs: 10,
3763
+ turnOffsetMs: 3
3764
+ },
3765
+ {
3766
+ description: "Appointment scheduler with short structured turns and reliable follow-up capture.",
3767
+ id: "appointment-scheduler",
3768
+ label: "Appointment scheduler",
3769
+ liveOffsetMs: 29,
3770
+ providerOffsetMs: 35,
3771
+ runtimeOffsetMs: 16,
3772
+ turnOffsetMs: 5
3773
+ },
3774
+ {
3775
+ description: "Noisy phone call with stricter transport and interruption proof requirements.",
3776
+ id: "noisy-phone-call",
3777
+ label: "Noisy phone call",
3778
+ liveOffsetMs: 40,
3779
+ providerOffsetMs: 60,
3780
+ runtimeOffsetMs: 22,
3781
+ turnOffsetMs: 7
3782
+ }
3783
+ ];
3750
3784
  var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
3751
3785
  var toTimeMs = (value) => {
3752
3786
  if (value instanceof Date) {
@@ -3839,6 +3873,95 @@ var readProofTrendRuntimeChannel = (report) => ({
3839
3873
  samples: report.summary.runtimeChannel?.samples ?? maxNumber(report.cycles.map((cycle) => cycle.runtimeChannel?.samples)),
3840
3874
  status: report.summary.runtimeChannel?.status
3841
3875
  });
3876
+ var addProofTrendProfileOffset = (value, offset, cap) => {
3877
+ if (value === undefined) {
3878
+ return;
3879
+ }
3880
+ const nextValue = Math.round(value + (offset ?? 0));
3881
+ return cap === undefined ? nextValue : Math.min(cap, nextValue);
3882
+ };
3883
+ var aggregateProofTrendProviders = (providers) => {
3884
+ const providersById = new Map;
3885
+ for (const provider of providers) {
3886
+ if (!provider.id) {
3887
+ continue;
3888
+ }
3889
+ const existing = providersById.get(provider.id);
3890
+ providersById.set(provider.id, {
3891
+ averageMs: maxNumber([existing?.averageMs, provider.averageMs]),
3892
+ id: provider.id,
3893
+ label: existing?.label ?? provider.label,
3894
+ p50Ms: maxNumber([existing?.p50Ms, provider.p50Ms]),
3895
+ p95Ms: maxNumber([existing?.p95Ms, provider.p95Ms]),
3896
+ role: existing?.role ?? provider.role,
3897
+ samples: (existing?.samples ?? 0) + (provider.samples ?? 0),
3898
+ status: existing?.status === "fail" || provider.status === "fail" ? "fail" : existing?.status === "warn" || provider.status === "warn" ? "warn" : provider.status ?? existing?.status
3899
+ });
3900
+ }
3901
+ return [...providersById.values()].sort((left, right) => (left.p95Ms ?? Number.POSITIVE_INFINITY) - (right.p95Ms ?? Number.POSITIVE_INFINITY));
3902
+ };
3903
+ var aggregateProofTrendRuntimeChannel = (channels) => {
3904
+ if (channels.length === 0) {
3905
+ return;
3906
+ }
3907
+ return {
3908
+ maxBackpressureEvents: maxNumber(channels.map((channel) => channel.maxBackpressureEvents)),
3909
+ maxFirstAudioLatencyMs: maxNumber(channels.map((channel) => channel.maxFirstAudioLatencyMs)),
3910
+ maxInterruptionP95Ms: maxNumber(channels.map((channel) => channel.maxInterruptionP95Ms)),
3911
+ maxJitterMs: maxNumber(channels.map((channel) => channel.maxJitterMs)),
3912
+ maxTimestampDriftMs: maxNumber(channels.map((channel) => channel.maxTimestampDriftMs)),
3913
+ samples: maxNumber(channels.map((channel) => channel.samples)),
3914
+ status: channels.some((channel) => channel.status === "fail") ? "fail" : channels.some((channel) => channel.status === "warn") ? "warn" : channels.every((channel) => channel.status === "pass") ? "pass" : undefined
3915
+ };
3916
+ };
3917
+ var readProofTrendProviders = (reports) => aggregateProofTrendProviders(reports.flatMap((report) => report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : report.cycles.flatMap((cycle) => cycle.providers ?? [])));
3918
+ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
3919
+ const reports = Array.isArray(input) ? input : [input];
3920
+ const definitions = options.profiles ?? DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS;
3921
+ const providerCap = options.maxProviderP95Ms ?? 1000;
3922
+ const liveCap = options.maxLiveP95Ms ?? 800;
3923
+ const turnCap = options.maxTurnP95Ms ?? 700;
3924
+ const runtimeFirstAudioCap = options.maxRuntimeFirstAudioLatencyMs ?? 600;
3925
+ const runtimeInterruptionCap = options.maxRuntimeInterruptionP95Ms ?? 300;
3926
+ const runtimeJitterCap = options.maxRuntimeJitterMs ?? 30;
3927
+ const runtimeTimestampDriftCap = options.maxRuntimeTimestampDriftMs ?? 800;
3928
+ return definitions.map((definition) => {
3929
+ const historicalProfiles = reports.flatMap((report) => report.summary.profiles?.filter((profile) => profile.id === definition.id) ?? []);
3930
+ if (historicalProfiles.length > 0) {
3931
+ return {
3932
+ description: definition.description ?? historicalProfiles.find(Boolean)?.description,
3933
+ id: definition.id,
3934
+ label: definition.label ?? historicalProfiles.find(Boolean)?.label,
3935
+ maxLiveP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxLiveP95Ms)),
3936
+ maxProviderP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxProviderP95Ms)),
3937
+ maxTurnP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxTurnP95Ms)),
3938
+ providers: aggregateProofTrendProviders(historicalProfiles.flatMap((profile) => profile.providers ?? [])),
3939
+ runtimeChannel: aggregateProofTrendRuntimeChannel(historicalProfiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined)),
3940
+ status: historicalProfiles.some((profile) => profile.status === "fail") ? "fail" : historicalProfiles.some((profile) => profile.status === "warn") ? "warn" : historicalProfiles.every((profile) => profile.status === "pass") ? "pass" : undefined
3941
+ };
3942
+ }
3943
+ const runtimeChannel = aggregateProofTrendRuntimeChannel(reports.map((report) => readProofTrendRuntimeChannel(report)).filter((channel) => Object.values(channel).some((value) => value !== undefined)));
3944
+ return {
3945
+ description: definition.description,
3946
+ id: definition.id,
3947
+ label: definition.label,
3948
+ maxLiveP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxLiveP95)), definition.liveOffsetMs, definition.maxLiveP95Ms ?? liveCap),
3949
+ maxProviderP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxProviderP95)), definition.providerOffsetMs, definition.maxProviderP95Ms ?? providerCap),
3950
+ maxTurnP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxTurnP95)), definition.turnOffsetMs, definition.maxTurnP95Ms ?? turnCap),
3951
+ providers: readProofTrendProviders(reports),
3952
+ runtimeChannel: runtimeChannel === undefined ? undefined : {
3953
+ maxBackpressureEvents: runtimeChannel.maxBackpressureEvents,
3954
+ maxFirstAudioLatencyMs: addProofTrendProfileOffset(runtimeChannel.maxFirstAudioLatencyMs, definition.runtimeOffsetMs, definition.maxRuntimeFirstAudioLatencyMs ?? runtimeFirstAudioCap),
3955
+ maxInterruptionP95Ms: addProofTrendProfileOffset(runtimeChannel.maxInterruptionP95Ms, Math.ceil((definition.runtimeOffsetMs ?? 0) / 2), definition.maxRuntimeInterruptionP95Ms ?? runtimeInterruptionCap),
3956
+ maxJitterMs: addProofTrendProfileOffset(runtimeChannel.maxJitterMs, Math.ceil((definition.runtimeOffsetMs ?? 0) / 4), definition.maxRuntimeJitterMs ?? runtimeJitterCap),
3957
+ maxTimestampDriftMs: addProofTrendProfileOffset(runtimeChannel.maxTimestampDriftMs, definition.runtimeOffsetMs, definition.maxRuntimeTimestampDriftMs ?? runtimeTimestampDriftCap),
3958
+ samples: runtimeChannel.samples,
3959
+ status: runtimeChannel.status
3960
+ },
3961
+ status: reports.some((report) => report.status === "fail" || !report.ok) ? "fail" : reports.some((report) => report.status === "warn") ? "warn" : reports.every((report) => report.ok) ? "pass" : undefined
3962
+ };
3963
+ });
3964
+ };
3842
3965
  var normalizeProviderStatus = (status) => status === "pass" ? "pass" : status === "fail" ? "fail" : "warn";
3843
3966
  var providerSortScore = (provider) => [
3844
3967
  recommendationStatusRank[provider.status],
@@ -3936,6 +4059,34 @@ var bestProviderByRole = (providers) => {
3936
4059
  return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
3937
4060
  };
3938
4061
  var formatProviderMix = (providers) => providers.length === 0 ? "n/a" : providers.map((provider) => provider.role && !(provider.label ?? provider.id).toLowerCase().startsWith(provider.role.toLowerCase()) ? `${provider.role.toUpperCase()} ${provider.label ?? provider.id}` : provider.label ?? provider.id).join(", ");
4062
+ var buildProfileRecommendations = (report, budgets) => (report.summary.profiles ?? []).map((profile) => {
4063
+ const providers = summarizeProofTrendProviders({
4064
+ ...report,
4065
+ cycles: [],
4066
+ summary: {
4067
+ cycles: report.summary.cycles,
4068
+ maxLiveP95Ms: profile.maxLiveP95Ms,
4069
+ maxProviderP95Ms: profile.maxProviderP95Ms,
4070
+ maxTurnP95Ms: profile.maxTurnP95Ms,
4071
+ providers: profile.providers,
4072
+ runtimeChannel: profile.runtimeChannel
4073
+ }
4074
+ }, budgets.maxProviderP95Ms);
4075
+ const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
4076
+ const hasRequiredProviderRoles = bestProviders.some((provider) => provider.role === "llm") && bestProviders.some((provider) => provider.role === "stt") && bestProviders.some((provider) => provider.role === "tts");
4077
+ const runtimePass = (profile.runtimeChannel?.status === undefined || profile.runtimeChannel.status === "pass") && (profile.runtimeChannel?.maxFirstAudioLatencyMs === undefined || profile.runtimeChannel.maxFirstAudioLatencyMs <= budgets.maxRuntimeFirstAudioLatencyMs) && (profile.runtimeChannel?.maxInterruptionP95Ms === undefined || profile.runtimeChannel.maxInterruptionP95Ms <= budgets.maxRuntimeInterruptionP95Ms) && (profile.runtimeChannel?.maxJitterMs === undefined || profile.runtimeChannel.maxJitterMs <= budgets.maxRuntimeJitterMs) && (profile.runtimeChannel?.maxTimestampDriftMs === undefined || profile.runtimeChannel.maxTimestampDriftMs <= budgets.maxRuntimeTimestampDriftMs) && (profile.runtimeChannel?.maxBackpressureEvents === undefined || profile.runtimeChannel.maxBackpressureEvents <= budgets.maxRuntimeBackpressureEvents);
4078
+ const latencyPass = (profile.maxProviderP95Ms === undefined || profile.maxProviderP95Ms <= budgets.maxProviderP95Ms) && (profile.maxLiveP95Ms === undefined || profile.maxLiveP95Ms <= budgets.maxLiveP95Ms) && (profile.maxTurnP95Ms === undefined || profile.maxTurnP95Ms <= budgets.maxTurnP95Ms);
4079
+ const status = profile.status === "fail" || !runtimePass ? "fail" : !latencyPass || !hasRequiredProviderRoles ? "warn" : "pass";
4080
+ return {
4081
+ bestProviders,
4082
+ id: profile.id,
4083
+ label: profile.label,
4084
+ nextMove: status === "pass" ? `Use this proven provider mix for ${profile.label ?? profile.id}: ${formatProviderMix(bestProviders)}.` : providers.length === 0 ? `Collect provider-specific sustained samples for ${profile.label ?? profile.id}.` : `Tune latency/runtime budgets for ${profile.label ?? profile.id} before promoting this profile.`,
4085
+ providerComparisonCount: providers.length,
4086
+ recommendation: status === "pass" ? `Profile ready: ${profile.label ?? profile.id}` : `Profile needs proof: ${profile.label ?? profile.id}`,
4087
+ status
4088
+ };
4089
+ });
3939
4090
  var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
3940
4091
  const issues = [];
3941
4092
  const requiredStatus = input.requireStatus ?? "pass";
@@ -4057,6 +4208,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
4057
4208
  const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
4058
4209
  const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
4059
4210
  const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
4211
+ const profileRecommendations = buildProfileRecommendations(report, budgets);
4060
4212
  const recommendations = [];
4061
4213
  const issues = [];
4062
4214
  if (report.ok !== true) {
@@ -4119,16 +4271,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
4119
4271
  surface: "turn-latency"
4120
4272
  });
4121
4273
  const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
4274
+ const profileStatus = worstRecommendationStatus(profileRecommendations.map((profile) => ({
4275
+ evidence: {},
4276
+ nextMove: profile.nextMove,
4277
+ recommendation: profile.recommendation,
4278
+ status: profile.status,
4279
+ surface: "provider-path"
4280
+ })));
4281
+ const combinedStatus = recommendationStatusRank[profileStatus] > recommendationStatusRank[status] ? profileStatus : status;
4122
4282
  return {
4123
4283
  bestProvider,
4124
4284
  bestProviders,
4125
4285
  generatedAt: new Date().toISOString(),
4126
4286
  issues,
4127
- ok: status !== "fail",
4287
+ ok: combinedStatus !== "fail",
4288
+ profiles: profileRecommendations,
4128
4289
  providers,
4129
4290
  recommendations,
4130
4291
  source: report.source || report.outputDir || report.runId || "proof-trends",
4131
- status,
4292
+ status: combinedStatus,
4132
4293
  summary: {
4133
4294
  keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
4134
4295
  keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
@@ -4159,6 +4320,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
4159
4320
  "| ---: | --- | --- | --- | ---: | ---: | --- |",
4160
4321
  ...report.providers.length ? report.providers.map((provider) => `| ${String(provider.rank)} | ${escapeMarkdown(provider.label ?? provider.id)} | ${escapeMarkdown(provider.role ?? "n/a")} | ${provider.status} | ${provider.p95Ms === undefined ? "n/a" : String(provider.p95Ms)} | ${provider.samples === undefined ? "n/a" : String(provider.samples)} | ${escapeMarkdown(provider.nextMove)} |`) : ["| n/a | n/a | n/a | n/a | n/a | n/a | No provider-specific samples were present. |"],
4161
4322
  "",
4323
+ "## Benchmark Profiles",
4324
+ "",
4325
+ "| Profile | Status | Provider mix | Next move |",
4326
+ "| --- | --- | --- | --- |",
4327
+ ...report.profiles.length ? report.profiles.map((profile) => `| ${escapeMarkdown(profile.label ?? profile.id)} | ${profile.status} | ${escapeMarkdown(formatProviderMix(profile.bestProviders))} | ${escapeMarkdown(profile.nextMove)} |`) : ["| n/a | n/a | n/a | No benchmark profiles were present. |"],
4328
+ "",
4162
4329
  "## Issues",
4163
4330
  "",
4164
4331
  ...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
@@ -4168,7 +4335,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
4168
4335
  const cards = report.recommendations.map((recommendation) => `<article class="${escapeHtml3(recommendation.status)}"><p class="eyebrow">${escapeHtml3(recommendation.surface)} \xB7 ${escapeHtml3(recommendation.status)}</p><h2>${escapeHtml3(recommendation.recommendation)}</h2><p>${escapeHtml3(recommendation.nextMove)}</p><pre>${escapeHtml3(JSON.stringify(recommendation.evidence, null, 2))}</pre></article>`).join("");
4169
4336
  const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml3(issue)}</li>`).join("");
4170
4337
  const providerRows = report.providers.length === 0 ? "<li>No provider-specific samples were present.</li>" : report.providers.map((provider) => `<li><strong>#${String(provider.rank)} ${escapeHtml3(provider.label ?? provider.id)}</strong><span>${escapeHtml3(provider.role ?? "provider")} \xB7 ${escapeHtml3(provider.status)} \xB7 p95 ${escapeHtml3(provider.p95Ms ?? "n/a")}ms \xB7 ${escapeHtml3(provider.samples ?? "n/a")} sample(s)</span><small>${escapeHtml3(provider.nextMove)}</small></li>`).join("");
4171
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml3(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}li{margin:.45rem 0}li span,li small{display:block;color:#c9d3ca}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml3(title)}</h1><p>Generated ${escapeHtml3(report.generatedAt)} from ${escapeHtml3(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml3(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Best mix ${escapeHtml3(formatProviderMix(report.bestProviders))}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Provider Comparison</h2><ul>${providerRows}</ul></section><section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
4338
+ const profileRows = report.profiles.length === 0 ? "<li>No benchmark profiles were present.</li>" : report.profiles.map((profile) => `<li><strong>${escapeHtml3(profile.label ?? profile.id)}</strong><span>${escapeHtml3(profile.status)} \xB7 ${escapeHtml3(formatProviderMix(profile.bestProviders))}</span><small>${escapeHtml3(profile.nextMove)}</small></li>`).join("");
4339
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml3(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}li{margin:.45rem 0}li span,li small{display:block;color:#c9d3ca}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml3(title)}</h1><p>Generated ${escapeHtml3(report.generatedAt)} from ${escapeHtml3(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml3(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Best mix ${escapeHtml3(formatProviderMix(report.bestProviders))}</span><span class="pill">Profiles ${String(report.profiles.length)}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Benchmark Profiles</h2><ul>${profileRows}</ul></section><section class="hero"><h2>Provider Comparison</h2><ul>${providerRows}</ul></section><section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
4172
4340
  };
4173
4341
  var createVoiceProofTrendRecommendationRoutes = (options) => {
4174
4342
  const path = options.path ?? "/api/voice/proof-trend-recommendations";
package/dist/index.d.ts CHANGED
@@ -28,10 +28,10 @@ export { assertVoicePlatformCoverage, buildVoicePlatformCoverageSummary, createV
28
28
  export { assertVoiceCompetitiveCoverage, buildVoiceCompetitiveCoverageReport, createVoiceCompetitiveCoverageRoutes, evaluateVoiceCompetitiveCoverage, renderVoiceCompetitiveCoverageHTML, renderVoiceCompetitiveCoverageMarkdown } from './competitiveCoverage';
29
29
  export type { VoiceCompetitiveCoverageAssertionInput, VoiceCompetitiveCoverageAssertionReport, VoiceCompetitiveCoverageIssue, VoiceCompetitiveCoverageLevel, VoiceCompetitiveCoverageReport, VoiceCompetitiveCoverageReportInput, VoiceCompetitiveCoverageRoutesOptions, VoiceCompetitiveCoverageStatus, VoiceCompetitiveCoverageSummary, VoiceCompetitiveDepthLevel, VoiceCompetitiveEvidence, VoiceCompetitiveSurface } from './competitiveCoverage';
30
30
  export type { VoicePlatformCoverageAssertionInput, VoicePlatformCoverageAssertionReport, VoicePlatformCoverageEvidence, VoicePlatformCoverageRoutesOptions, VoicePlatformCoverageStatus, VoicePlatformCoverageSummary, VoicePlatformCoverageSummaryInput, VoicePlatformCoverageSurface } from './platformCoverage';
31
- export { assertVoiceProofTrendEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReport, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown } from './proofTrends';
31
+ export { assertVoiceProofTrendEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendProfileSummaries, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReport, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown } from './proofTrends';
32
32
  export { buildVoiceProviderDecisionTraceReport, createVoiceProviderDecisionTraceEvent, createVoiceProviderDecisionTraceRoutes, listVoiceProviderDecisionTraces, renderVoiceProviderDecisionTraceHTML, renderVoiceProviderDecisionTraceMarkdown } from './providerDecisionTraces';
33
33
  export type { VoiceProviderDecisionStatus, VoiceProviderDecisionSurfaceReport, VoiceProviderDecisionTrace, VoiceProviderDecisionTraceInput, VoiceProviderDecisionTraceIssue, VoiceProviderDecisionTraceReport, VoiceProviderDecisionTraceReportOptions, VoiceProviderDecisionTraceRoutesOptions } from './providerDecisionTraces';
34
- export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendProviderRecommendation, VoiceProofTrendProviderSummary, VoiceProofTrendRecommendation, VoiceProofTrendRecommendationOptions, VoiceProofTrendRecommendationReport, VoiceProofTrendRecommendationRoutesOptions, VoiceProofTrendRecommendationStatus, VoiceProofTrendRecommendationSurface, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendStatus, VoiceProofTrendSummary } from './proofTrends';
34
+ export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendProfileDefinition, VoiceProofTrendProfileRecommendation, VoiceProofTrendProfileSummaryOptions, VoiceProofTrendProfileSummary, VoiceProofTrendProviderRecommendation, VoiceProofTrendProviderSummary, VoiceProofTrendRecommendation, VoiceProofTrendRecommendationOptions, VoiceProofTrendRecommendationReport, VoiceProofTrendRecommendationRoutesOptions, VoiceProofTrendRecommendationStatus, VoiceProofTrendRecommendationSurface, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendStatus, VoiceProofTrendSummary } from './proofTrends';
35
35
  export { assertVoiceSloCalibration, buildVoiceSloCalibrationReport, buildVoiceSloReadinessThresholdReport, createVoiceSloReadinessThresholdOptions, createVoiceSloReadinessThresholdRoutes, createVoiceSloThresholdProfile, createVoiceSloCalibrationRoutes, renderVoiceSloCalibrationMarkdown, renderVoiceSloReadinessThresholdHTML, renderVoiceSloReadinessThresholdMarkdown } from './sloCalibration';
36
36
  export type { VoiceSloCalibrationMetricKey, VoiceSloCalibrationOptions, VoiceSloCalibrationReport, VoiceSloCalibrationRoutesOptions, VoiceSloCalibrationSample, VoiceSloCalibrationStatus, VoiceSloCalibrationThreshold, VoiceSloCalibrationThresholds, VoiceSloReadinessThresholdReport, VoiceSloReadinessThresholdReportOptions, VoiceSloReadinessThresholdOptions, VoiceSloReadinessThresholdRoutesOptions, VoiceSloThresholdProfile } from './sloCalibration';
37
37
  export { assertVoiceLiveOpsControlEvidence, assertVoiceLiveOpsEvidence, buildVoiceLiveOpsControlState, createVoiceLiveOpsController, createVoiceLiveOpsRoutes, createVoiceMemoryLiveOpsControlStore, evaluateVoiceLiveOpsControlEvidence, evaluateVoiceLiveOpsEvidence, getVoiceLiveOpsControlStatus, VOICE_LIVE_OPS_ACTIONS } from './liveOps';
package/dist/index.js CHANGED
@@ -14464,6 +14464,40 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
14464
14464
  // src/proofTrends.ts
14465
14465
  import { Elysia as Elysia20 } from "elysia";
14466
14466
  var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
14467
+ var DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS = [
14468
+ {
14469
+ description: "Browser recorder with longer passive listening and transcript capture.",
14470
+ id: "meeting-recorder",
14471
+ label: "Meeting recorder"
14472
+ },
14473
+ {
14474
+ description: "Realtime support agent with fast interruption recovery and tool-ready turns.",
14475
+ id: "support-agent",
14476
+ label: "Support agent",
14477
+ liveOffsetMs: 17,
14478
+ providerOffsetMs: 20,
14479
+ runtimeOffsetMs: 10,
14480
+ turnOffsetMs: 3
14481
+ },
14482
+ {
14483
+ description: "Appointment scheduler with short structured turns and reliable follow-up capture.",
14484
+ id: "appointment-scheduler",
14485
+ label: "Appointment scheduler",
14486
+ liveOffsetMs: 29,
14487
+ providerOffsetMs: 35,
14488
+ runtimeOffsetMs: 16,
14489
+ turnOffsetMs: 5
14490
+ },
14491
+ {
14492
+ description: "Noisy phone call with stricter transport and interruption proof requirements.",
14493
+ id: "noisy-phone-call",
14494
+ label: "Noisy phone call",
14495
+ liveOffsetMs: 40,
14496
+ providerOffsetMs: 60,
14497
+ runtimeOffsetMs: 22,
14498
+ turnOffsetMs: 7
14499
+ }
14500
+ ];
14467
14501
  var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
14468
14502
  var toTimeMs = (value) => {
14469
14503
  if (value instanceof Date) {
@@ -14556,6 +14590,95 @@ var readProofTrendRuntimeChannel = (report) => ({
14556
14590
  samples: report.summary.runtimeChannel?.samples ?? maxNumber(report.cycles.map((cycle) => cycle.runtimeChannel?.samples)),
14557
14591
  status: report.summary.runtimeChannel?.status
14558
14592
  });
14593
+ var addProofTrendProfileOffset = (value, offset, cap) => {
14594
+ if (value === undefined) {
14595
+ return;
14596
+ }
14597
+ const nextValue = Math.round(value + (offset ?? 0));
14598
+ return cap === undefined ? nextValue : Math.min(cap, nextValue);
14599
+ };
14600
+ var aggregateProofTrendProviders = (providers) => {
14601
+ const providersById = new Map;
14602
+ for (const provider of providers) {
14603
+ if (!provider.id) {
14604
+ continue;
14605
+ }
14606
+ const existing = providersById.get(provider.id);
14607
+ providersById.set(provider.id, {
14608
+ averageMs: maxNumber([existing?.averageMs, provider.averageMs]),
14609
+ id: provider.id,
14610
+ label: existing?.label ?? provider.label,
14611
+ p50Ms: maxNumber([existing?.p50Ms, provider.p50Ms]),
14612
+ p95Ms: maxNumber([existing?.p95Ms, provider.p95Ms]),
14613
+ role: existing?.role ?? provider.role,
14614
+ samples: (existing?.samples ?? 0) + (provider.samples ?? 0),
14615
+ status: existing?.status === "fail" || provider.status === "fail" ? "fail" : existing?.status === "warn" || provider.status === "warn" ? "warn" : provider.status ?? existing?.status
14616
+ });
14617
+ }
14618
+ return [...providersById.values()].sort((left, right) => (left.p95Ms ?? Number.POSITIVE_INFINITY) - (right.p95Ms ?? Number.POSITIVE_INFINITY));
14619
+ };
14620
+ var aggregateProofTrendRuntimeChannel = (channels) => {
14621
+ if (channels.length === 0) {
14622
+ return;
14623
+ }
14624
+ return {
14625
+ maxBackpressureEvents: maxNumber(channels.map((channel) => channel.maxBackpressureEvents)),
14626
+ maxFirstAudioLatencyMs: maxNumber(channels.map((channel) => channel.maxFirstAudioLatencyMs)),
14627
+ maxInterruptionP95Ms: maxNumber(channels.map((channel) => channel.maxInterruptionP95Ms)),
14628
+ maxJitterMs: maxNumber(channels.map((channel) => channel.maxJitterMs)),
14629
+ maxTimestampDriftMs: maxNumber(channels.map((channel) => channel.maxTimestampDriftMs)),
14630
+ samples: maxNumber(channels.map((channel) => channel.samples)),
14631
+ status: channels.some((channel) => channel.status === "fail") ? "fail" : channels.some((channel) => channel.status === "warn") ? "warn" : channels.every((channel) => channel.status === "pass") ? "pass" : undefined
14632
+ };
14633
+ };
14634
+ var readProofTrendProviders = (reports) => aggregateProofTrendProviders(reports.flatMap((report) => report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : report.cycles.flatMap((cycle) => cycle.providers ?? [])));
14635
+ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
14636
+ const reports = Array.isArray(input) ? input : [input];
14637
+ const definitions = options.profiles ?? DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS;
14638
+ const providerCap = options.maxProviderP95Ms ?? 1000;
14639
+ const liveCap = options.maxLiveP95Ms ?? 800;
14640
+ const turnCap = options.maxTurnP95Ms ?? 700;
14641
+ const runtimeFirstAudioCap = options.maxRuntimeFirstAudioLatencyMs ?? 600;
14642
+ const runtimeInterruptionCap = options.maxRuntimeInterruptionP95Ms ?? 300;
14643
+ const runtimeJitterCap = options.maxRuntimeJitterMs ?? 30;
14644
+ const runtimeTimestampDriftCap = options.maxRuntimeTimestampDriftMs ?? 800;
14645
+ return definitions.map((definition) => {
14646
+ const historicalProfiles = reports.flatMap((report) => report.summary.profiles?.filter((profile) => profile.id === definition.id) ?? []);
14647
+ if (historicalProfiles.length > 0) {
14648
+ return {
14649
+ description: definition.description ?? historicalProfiles.find(Boolean)?.description,
14650
+ id: definition.id,
14651
+ label: definition.label ?? historicalProfiles.find(Boolean)?.label,
14652
+ maxLiveP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxLiveP95Ms)),
14653
+ maxProviderP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxProviderP95Ms)),
14654
+ maxTurnP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxTurnP95Ms)),
14655
+ providers: aggregateProofTrendProviders(historicalProfiles.flatMap((profile) => profile.providers ?? [])),
14656
+ runtimeChannel: aggregateProofTrendRuntimeChannel(historicalProfiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined)),
14657
+ status: historicalProfiles.some((profile) => profile.status === "fail") ? "fail" : historicalProfiles.some((profile) => profile.status === "warn") ? "warn" : historicalProfiles.every((profile) => profile.status === "pass") ? "pass" : undefined
14658
+ };
14659
+ }
14660
+ const runtimeChannel = aggregateProofTrendRuntimeChannel(reports.map((report) => readProofTrendRuntimeChannel(report)).filter((channel) => Object.values(channel).some((value) => value !== undefined)));
14661
+ return {
14662
+ description: definition.description,
14663
+ id: definition.id,
14664
+ label: definition.label,
14665
+ maxLiveP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxLiveP95)), definition.liveOffsetMs, definition.maxLiveP95Ms ?? liveCap),
14666
+ maxProviderP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxProviderP95)), definition.providerOffsetMs, definition.maxProviderP95Ms ?? providerCap),
14667
+ maxTurnP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxTurnP95)), definition.turnOffsetMs, definition.maxTurnP95Ms ?? turnCap),
14668
+ providers: readProofTrendProviders(reports),
14669
+ runtimeChannel: runtimeChannel === undefined ? undefined : {
14670
+ maxBackpressureEvents: runtimeChannel.maxBackpressureEvents,
14671
+ maxFirstAudioLatencyMs: addProofTrendProfileOffset(runtimeChannel.maxFirstAudioLatencyMs, definition.runtimeOffsetMs, definition.maxRuntimeFirstAudioLatencyMs ?? runtimeFirstAudioCap),
14672
+ maxInterruptionP95Ms: addProofTrendProfileOffset(runtimeChannel.maxInterruptionP95Ms, Math.ceil((definition.runtimeOffsetMs ?? 0) / 2), definition.maxRuntimeInterruptionP95Ms ?? runtimeInterruptionCap),
14673
+ maxJitterMs: addProofTrendProfileOffset(runtimeChannel.maxJitterMs, Math.ceil((definition.runtimeOffsetMs ?? 0) / 4), definition.maxRuntimeJitterMs ?? runtimeJitterCap),
14674
+ maxTimestampDriftMs: addProofTrendProfileOffset(runtimeChannel.maxTimestampDriftMs, definition.runtimeOffsetMs, definition.maxRuntimeTimestampDriftMs ?? runtimeTimestampDriftCap),
14675
+ samples: runtimeChannel.samples,
14676
+ status: runtimeChannel.status
14677
+ },
14678
+ status: reports.some((report) => report.status === "fail" || !report.ok) ? "fail" : reports.some((report) => report.status === "warn") ? "warn" : reports.every((report) => report.ok) ? "pass" : undefined
14679
+ };
14680
+ });
14681
+ };
14559
14682
  var normalizeProviderStatus = (status) => status === "pass" ? "pass" : status === "fail" ? "fail" : "warn";
14560
14683
  var providerSortScore = (provider) => [
14561
14684
  recommendationStatusRank[provider.status],
@@ -14653,6 +14776,34 @@ var bestProviderByRole = (providers) => {
14653
14776
  return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
14654
14777
  };
14655
14778
  var formatProviderMix = (providers) => providers.length === 0 ? "n/a" : providers.map((provider) => provider.role && !(provider.label ?? provider.id).toLowerCase().startsWith(provider.role.toLowerCase()) ? `${provider.role.toUpperCase()} ${provider.label ?? provider.id}` : provider.label ?? provider.id).join(", ");
14779
+ var buildProfileRecommendations = (report, budgets) => (report.summary.profiles ?? []).map((profile) => {
14780
+ const providers = summarizeProofTrendProviders({
14781
+ ...report,
14782
+ cycles: [],
14783
+ summary: {
14784
+ cycles: report.summary.cycles,
14785
+ maxLiveP95Ms: profile.maxLiveP95Ms,
14786
+ maxProviderP95Ms: profile.maxProviderP95Ms,
14787
+ maxTurnP95Ms: profile.maxTurnP95Ms,
14788
+ providers: profile.providers,
14789
+ runtimeChannel: profile.runtimeChannel
14790
+ }
14791
+ }, budgets.maxProviderP95Ms);
14792
+ const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
14793
+ const hasRequiredProviderRoles = bestProviders.some((provider) => provider.role === "llm") && bestProviders.some((provider) => provider.role === "stt") && bestProviders.some((provider) => provider.role === "tts");
14794
+ const runtimePass = (profile.runtimeChannel?.status === undefined || profile.runtimeChannel.status === "pass") && (profile.runtimeChannel?.maxFirstAudioLatencyMs === undefined || profile.runtimeChannel.maxFirstAudioLatencyMs <= budgets.maxRuntimeFirstAudioLatencyMs) && (profile.runtimeChannel?.maxInterruptionP95Ms === undefined || profile.runtimeChannel.maxInterruptionP95Ms <= budgets.maxRuntimeInterruptionP95Ms) && (profile.runtimeChannel?.maxJitterMs === undefined || profile.runtimeChannel.maxJitterMs <= budgets.maxRuntimeJitterMs) && (profile.runtimeChannel?.maxTimestampDriftMs === undefined || profile.runtimeChannel.maxTimestampDriftMs <= budgets.maxRuntimeTimestampDriftMs) && (profile.runtimeChannel?.maxBackpressureEvents === undefined || profile.runtimeChannel.maxBackpressureEvents <= budgets.maxRuntimeBackpressureEvents);
14795
+ const latencyPass = (profile.maxProviderP95Ms === undefined || profile.maxProviderP95Ms <= budgets.maxProviderP95Ms) && (profile.maxLiveP95Ms === undefined || profile.maxLiveP95Ms <= budgets.maxLiveP95Ms) && (profile.maxTurnP95Ms === undefined || profile.maxTurnP95Ms <= budgets.maxTurnP95Ms);
14796
+ const status = profile.status === "fail" || !runtimePass ? "fail" : !latencyPass || !hasRequiredProviderRoles ? "warn" : "pass";
14797
+ return {
14798
+ bestProviders,
14799
+ id: profile.id,
14800
+ label: profile.label,
14801
+ nextMove: status === "pass" ? `Use this proven provider mix for ${profile.label ?? profile.id}: ${formatProviderMix(bestProviders)}.` : providers.length === 0 ? `Collect provider-specific sustained samples for ${profile.label ?? profile.id}.` : `Tune latency/runtime budgets for ${profile.label ?? profile.id} before promoting this profile.`,
14802
+ providerComparisonCount: providers.length,
14803
+ recommendation: status === "pass" ? `Profile ready: ${profile.label ?? profile.id}` : `Profile needs proof: ${profile.label ?? profile.id}`,
14804
+ status
14805
+ };
14806
+ });
14656
14807
  var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
14657
14808
  const issues = [];
14658
14809
  const requiredStatus = input.requireStatus ?? "pass";
@@ -14774,6 +14925,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
14774
14925
  const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
14775
14926
  const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
14776
14927
  const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
14928
+ const profileRecommendations = buildProfileRecommendations(report, budgets);
14777
14929
  const recommendations = [];
14778
14930
  const issues = [];
14779
14931
  if (report.ok !== true) {
@@ -14836,16 +14988,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
14836
14988
  surface: "turn-latency"
14837
14989
  });
14838
14990
  const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
14991
+ const profileStatus = worstRecommendationStatus(profileRecommendations.map((profile) => ({
14992
+ evidence: {},
14993
+ nextMove: profile.nextMove,
14994
+ recommendation: profile.recommendation,
14995
+ status: profile.status,
14996
+ surface: "provider-path"
14997
+ })));
14998
+ const combinedStatus = recommendationStatusRank[profileStatus] > recommendationStatusRank[status] ? profileStatus : status;
14839
14999
  return {
14840
15000
  bestProvider,
14841
15001
  bestProviders,
14842
15002
  generatedAt: new Date().toISOString(),
14843
15003
  issues,
14844
- ok: status !== "fail",
15004
+ ok: combinedStatus !== "fail",
15005
+ profiles: profileRecommendations,
14845
15006
  providers,
14846
15007
  recommendations,
14847
15008
  source: report.source || report.outputDir || report.runId || "proof-trends",
14848
- status,
15009
+ status: combinedStatus,
14849
15010
  summary: {
14850
15011
  keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
14851
15012
  keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
@@ -14876,6 +15037,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
14876
15037
  "| ---: | --- | --- | --- | ---: | ---: | --- |",
14877
15038
  ...report.providers.length ? report.providers.map((provider) => `| ${String(provider.rank)} | ${escapeMarkdown2(provider.label ?? provider.id)} | ${escapeMarkdown2(provider.role ?? "n/a")} | ${provider.status} | ${provider.p95Ms === undefined ? "n/a" : String(provider.p95Ms)} | ${provider.samples === undefined ? "n/a" : String(provider.samples)} | ${escapeMarkdown2(provider.nextMove)} |`) : ["| n/a | n/a | n/a | n/a | n/a | n/a | No provider-specific samples were present. |"],
14878
15039
  "",
15040
+ "## Benchmark Profiles",
15041
+ "",
15042
+ "| Profile | Status | Provider mix | Next move |",
15043
+ "| --- | --- | --- | --- |",
15044
+ ...report.profiles.length ? report.profiles.map((profile) => `| ${escapeMarkdown2(profile.label ?? profile.id)} | ${profile.status} | ${escapeMarkdown2(formatProviderMix(profile.bestProviders))} | ${escapeMarkdown2(profile.nextMove)} |`) : ["| n/a | n/a | n/a | No benchmark profiles were present. |"],
15045
+ "",
14879
15046
  "## Issues",
14880
15047
  "",
14881
15048
  ...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
@@ -14885,7 +15052,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
14885
15052
  const cards = report.recommendations.map((recommendation) => `<article class="${escapeHtml22(recommendation.status)}"><p class="eyebrow">${escapeHtml22(recommendation.surface)} \xB7 ${escapeHtml22(recommendation.status)}</p><h2>${escapeHtml22(recommendation.recommendation)}</h2><p>${escapeHtml22(recommendation.nextMove)}</p><pre>${escapeHtml22(JSON.stringify(recommendation.evidence, null, 2))}</pre></article>`).join("");
14886
15053
  const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml22(issue)}</li>`).join("");
14887
15054
  const providerRows = report.providers.length === 0 ? "<li>No provider-specific samples were present.</li>" : report.providers.map((provider) => `<li><strong>#${String(provider.rank)} ${escapeHtml22(provider.label ?? provider.id)}</strong><span>${escapeHtml22(provider.role ?? "provider")} \xB7 ${escapeHtml22(provider.status)} \xB7 p95 ${escapeHtml22(provider.p95Ms ?? "n/a")}ms \xB7 ${escapeHtml22(provider.samples ?? "n/a")} sample(s)</span><small>${escapeHtml22(provider.nextMove)}</small></li>`).join("");
14888
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml22(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}li{margin:.45rem 0}li span,li small{display:block;color:#c9d3ca}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml22(title)}</h1><p>Generated ${escapeHtml22(report.generatedAt)} from ${escapeHtml22(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml22(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Best mix ${escapeHtml22(formatProviderMix(report.bestProviders))}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Provider Comparison</h2><ul>${providerRows}</ul></section><section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
15055
+ const profileRows = report.profiles.length === 0 ? "<li>No benchmark profiles were present.</li>" : report.profiles.map((profile) => `<li><strong>${escapeHtml22(profile.label ?? profile.id)}</strong><span>${escapeHtml22(profile.status)} \xB7 ${escapeHtml22(formatProviderMix(profile.bestProviders))}</span><small>${escapeHtml22(profile.nextMove)}</small></li>`).join("");
15056
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml22(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}li{margin:.45rem 0}li span,li small{display:block;color:#c9d3ca}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml22(title)}</h1><p>Generated ${escapeHtml22(report.generatedAt)} from ${escapeHtml22(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml22(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Best mix ${escapeHtml22(formatProviderMix(report.bestProviders))}</span><span class="pill">Profiles ${String(report.profiles.length)}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Benchmark Profiles</h2><ul>${profileRows}</ul></section><section class="hero"><h2>Provider Comparison</h2><ul>${providerRows}</ul></section><section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
14889
15057
  };
14890
15058
  var createVoiceProofTrendRecommendationRoutes = (options) => {
14891
15059
  const path = options.path ?? "/api/voice/proof-trend-recommendations";
@@ -36955,6 +37123,7 @@ export {
36955
37123
  buildVoiceProviderContractMatrix,
36956
37124
  buildVoiceProofTrendReport,
36957
37125
  buildVoiceProofTrendRecommendationReport,
37126
+ buildVoiceProofTrendProfileSummaries,
36958
37127
  buildVoiceProductionReadinessReport,
36959
37128
  buildVoiceProductionReadinessGate,
36960
37129
  buildVoicePostCallAnalysisReport,
@@ -37035,5 +37204,6 @@ export {
37035
37204
  acknowledgeVoiceMonitorIssue,
37036
37205
  VOICE_LIVE_OPS_ACTIONS,
37037
37206
  TURN_PROFILE_DEFAULTS,
37207
+ DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS,
37038
37208
  DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS
37039
37209
  };
@@ -4,10 +4,38 @@ export type VoiceProofTrendSummary = {
4
4
  cycles?: number;
5
5
  maxLiveP95Ms?: number;
6
6
  maxProviderP95Ms?: number;
7
+ profiles?: VoiceProofTrendProfileSummary[];
7
8
  providers?: VoiceProofTrendProviderSummary[];
8
9
  runtimeChannel?: VoiceProofTrendRuntimeChannelSummary;
9
10
  maxTurnP95Ms?: number;
10
11
  };
12
+ export type VoiceProofTrendProfileSummary = {
13
+ description?: string;
14
+ id: string;
15
+ label?: string;
16
+ maxLiveP95Ms?: number;
17
+ maxProviderP95Ms?: number;
18
+ maxTurnP95Ms?: number;
19
+ providers?: VoiceProofTrendProviderSummary[];
20
+ runtimeChannel?: VoiceProofTrendRuntimeChannelSummary;
21
+ status?: string;
22
+ };
23
+ export type VoiceProofTrendProfileDefinition = {
24
+ description?: string;
25
+ id: string;
26
+ label?: string;
27
+ liveOffsetMs?: number;
28
+ maxLiveP95Ms?: number;
29
+ maxProviderP95Ms?: number;
30
+ maxRuntimeFirstAudioLatencyMs?: number;
31
+ maxRuntimeInterruptionP95Ms?: number;
32
+ maxRuntimeJitterMs?: number;
33
+ maxRuntimeTimestampDriftMs?: number;
34
+ maxTurnP95Ms?: number;
35
+ providerOffsetMs?: number;
36
+ runtimeOffsetMs?: number;
37
+ turnOffsetMs?: number;
38
+ };
11
39
  export type VoiceProofTrendProviderSummary = {
12
40
  averageMs?: number;
13
41
  id: string;
@@ -82,6 +110,16 @@ export type VoiceProofTrendReport = {
82
110
  status: VoiceProofTrendStatus;
83
111
  summary: VoiceProofTrendSummary;
84
112
  };
113
+ export type VoiceProofTrendProfileSummaryOptions = {
114
+ maxLiveP95Ms?: number;
115
+ maxProviderP95Ms?: number;
116
+ maxRuntimeFirstAudioLatencyMs?: number;
117
+ maxRuntimeInterruptionP95Ms?: number;
118
+ maxRuntimeJitterMs?: number;
119
+ maxRuntimeTimestampDriftMs?: number;
120
+ maxTurnP95Ms?: number;
121
+ profiles?: readonly VoiceProofTrendProfileDefinition[];
122
+ };
85
123
  export type VoiceProofTrendAssertionInput = {
86
124
  maxAgeMs?: number;
87
125
  maxRuntimeBackpressureEvents?: number;
@@ -149,6 +187,7 @@ export type VoiceProofTrendRecommendationReport = {
149
187
  generatedAt: string;
150
188
  issues: string[];
151
189
  ok: boolean;
190
+ profiles: VoiceProofTrendProfileRecommendation[];
152
191
  providers: VoiceProofTrendProviderRecommendation[];
153
192
  recommendations: VoiceProofTrendRecommendation[];
154
193
  source: string;
@@ -161,6 +200,15 @@ export type VoiceProofTrendRecommendationReport = {
161
200
  switchRecommended: boolean;
162
201
  };
163
202
  };
203
+ export type VoiceProofTrendProfileRecommendation = {
204
+ bestProviders: VoiceProofTrendProviderRecommendation[];
205
+ id: string;
206
+ label?: string;
207
+ nextMove: string;
208
+ providerComparisonCount: number;
209
+ recommendation: string;
210
+ status: VoiceProofTrendRecommendationStatus;
211
+ };
164
212
  export type VoiceProofTrendRecommendationOptions = {
165
213
  currentProviderId?: string;
166
214
  maxLiveP95Ms?: number;
@@ -186,6 +234,23 @@ export type VoiceProofTrendRecommendationRoutesOptions = VoiceProofTrendRecommen
186
234
  title?: string;
187
235
  };
188
236
  export declare const DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS: number;
237
+ export declare const DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS: ({
238
+ description: string;
239
+ id: string;
240
+ label: string;
241
+ liveOffsetMs?: undefined;
242
+ providerOffsetMs?: undefined;
243
+ runtimeOffsetMs?: undefined;
244
+ turnOffsetMs?: undefined;
245
+ } | {
246
+ description: string;
247
+ id: string;
248
+ label: string;
249
+ liveOffsetMs: number;
250
+ providerOffsetMs: number;
251
+ runtimeOffsetMs: number;
252
+ turnOffsetMs: number;
253
+ })[];
189
254
  export declare const buildVoiceProofTrendReport: (input?: VoiceProofTrendReportInput) => VoiceProofTrendReport;
190
255
  export declare const buildEmptyVoiceProofTrendReport: (source?: string, maxAgeMs?: number) => VoiceProofTrendReport;
191
256
  export declare const normalizeVoiceProofTrendReport: (value: VoiceProofTrendReport | VoiceProofTrendReportInput, options?: {
@@ -195,6 +260,7 @@ export declare const normalizeVoiceProofTrendReport: (value: VoiceProofTrendRepo
195
260
  export declare const readVoiceProofTrendReportFile: (path: string, options?: {
196
261
  maxAgeMs?: number;
197
262
  }) => Promise<VoiceProofTrendReport>;
263
+ export declare const buildVoiceProofTrendProfileSummaries: (input: VoiceProofTrendReport | readonly VoiceProofTrendReport[], options?: VoiceProofTrendProfileSummaryOptions) => VoiceProofTrendProfileSummary[];
198
264
  export declare const evaluateVoiceProofTrendEvidence: (report: VoiceProofTrendReport, input?: VoiceProofTrendAssertionInput) => VoiceProofTrendAssertionReport;
199
265
  export declare const assertVoiceProofTrendEvidence: (report: VoiceProofTrendReport, input?: VoiceProofTrendAssertionInput) => VoiceProofTrendAssertionReport;
200
266
  export declare const buildVoiceProofTrendRecommendationReport: (report: VoiceProofTrendReport, options?: VoiceProofTrendRecommendationOptions) => VoiceProofTrendRecommendationReport;
@@ -1495,6 +1495,40 @@ var useVoiceProofTrends = (path = "/api/voice/proof-trends", options = {}) => {
1495
1495
  // src/proofTrends.ts
1496
1496
  import { Elysia } from "elysia";
1497
1497
  var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
1498
+ var DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS = [
1499
+ {
1500
+ description: "Browser recorder with longer passive listening and transcript capture.",
1501
+ id: "meeting-recorder",
1502
+ label: "Meeting recorder"
1503
+ },
1504
+ {
1505
+ description: "Realtime support agent with fast interruption recovery and tool-ready turns.",
1506
+ id: "support-agent",
1507
+ label: "Support agent",
1508
+ liveOffsetMs: 17,
1509
+ providerOffsetMs: 20,
1510
+ runtimeOffsetMs: 10,
1511
+ turnOffsetMs: 3
1512
+ },
1513
+ {
1514
+ description: "Appointment scheduler with short structured turns and reliable follow-up capture.",
1515
+ id: "appointment-scheduler",
1516
+ label: "Appointment scheduler",
1517
+ liveOffsetMs: 29,
1518
+ providerOffsetMs: 35,
1519
+ runtimeOffsetMs: 16,
1520
+ turnOffsetMs: 5
1521
+ },
1522
+ {
1523
+ description: "Noisy phone call with stricter transport and interruption proof requirements.",
1524
+ id: "noisy-phone-call",
1525
+ label: "Noisy phone call",
1526
+ liveOffsetMs: 40,
1527
+ providerOffsetMs: 60,
1528
+ runtimeOffsetMs: 22,
1529
+ turnOffsetMs: 7
1530
+ }
1531
+ ];
1498
1532
  var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
1499
1533
  var toTimeMs = (value) => {
1500
1534
  if (value instanceof Date) {
@@ -1587,6 +1621,95 @@ var readProofTrendRuntimeChannel = (report) => ({
1587
1621
  samples: report.summary.runtimeChannel?.samples ?? maxNumber(report.cycles.map((cycle) => cycle.runtimeChannel?.samples)),
1588
1622
  status: report.summary.runtimeChannel?.status
1589
1623
  });
1624
+ var addProofTrendProfileOffset = (value, offset, cap) => {
1625
+ if (value === undefined) {
1626
+ return;
1627
+ }
1628
+ const nextValue = Math.round(value + (offset ?? 0));
1629
+ return cap === undefined ? nextValue : Math.min(cap, nextValue);
1630
+ };
1631
+ var aggregateProofTrendProviders = (providers) => {
1632
+ const providersById = new Map;
1633
+ for (const provider of providers) {
1634
+ if (!provider.id) {
1635
+ continue;
1636
+ }
1637
+ const existing = providersById.get(provider.id);
1638
+ providersById.set(provider.id, {
1639
+ averageMs: maxNumber([existing?.averageMs, provider.averageMs]),
1640
+ id: provider.id,
1641
+ label: existing?.label ?? provider.label,
1642
+ p50Ms: maxNumber([existing?.p50Ms, provider.p50Ms]),
1643
+ p95Ms: maxNumber([existing?.p95Ms, provider.p95Ms]),
1644
+ role: existing?.role ?? provider.role,
1645
+ samples: (existing?.samples ?? 0) + (provider.samples ?? 0),
1646
+ status: existing?.status === "fail" || provider.status === "fail" ? "fail" : existing?.status === "warn" || provider.status === "warn" ? "warn" : provider.status ?? existing?.status
1647
+ });
1648
+ }
1649
+ return [...providersById.values()].sort((left, right) => (left.p95Ms ?? Number.POSITIVE_INFINITY) - (right.p95Ms ?? Number.POSITIVE_INFINITY));
1650
+ };
1651
+ var aggregateProofTrendRuntimeChannel = (channels) => {
1652
+ if (channels.length === 0) {
1653
+ return;
1654
+ }
1655
+ return {
1656
+ maxBackpressureEvents: maxNumber(channels.map((channel) => channel.maxBackpressureEvents)),
1657
+ maxFirstAudioLatencyMs: maxNumber(channels.map((channel) => channel.maxFirstAudioLatencyMs)),
1658
+ maxInterruptionP95Ms: maxNumber(channels.map((channel) => channel.maxInterruptionP95Ms)),
1659
+ maxJitterMs: maxNumber(channels.map((channel) => channel.maxJitterMs)),
1660
+ maxTimestampDriftMs: maxNumber(channels.map((channel) => channel.maxTimestampDriftMs)),
1661
+ samples: maxNumber(channels.map((channel) => channel.samples)),
1662
+ status: channels.some((channel) => channel.status === "fail") ? "fail" : channels.some((channel) => channel.status === "warn") ? "warn" : channels.every((channel) => channel.status === "pass") ? "pass" : undefined
1663
+ };
1664
+ };
1665
+ var readProofTrendProviders = (reports) => aggregateProofTrendProviders(reports.flatMap((report) => report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : report.cycles.flatMap((cycle) => cycle.providers ?? [])));
1666
+ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
1667
+ const reports = Array.isArray(input) ? input : [input];
1668
+ const definitions = options.profiles ?? DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS;
1669
+ const providerCap = options.maxProviderP95Ms ?? 1000;
1670
+ const liveCap = options.maxLiveP95Ms ?? 800;
1671
+ const turnCap = options.maxTurnP95Ms ?? 700;
1672
+ const runtimeFirstAudioCap = options.maxRuntimeFirstAudioLatencyMs ?? 600;
1673
+ const runtimeInterruptionCap = options.maxRuntimeInterruptionP95Ms ?? 300;
1674
+ const runtimeJitterCap = options.maxRuntimeJitterMs ?? 30;
1675
+ const runtimeTimestampDriftCap = options.maxRuntimeTimestampDriftMs ?? 800;
1676
+ return definitions.map((definition) => {
1677
+ const historicalProfiles = reports.flatMap((report) => report.summary.profiles?.filter((profile) => profile.id === definition.id) ?? []);
1678
+ if (historicalProfiles.length > 0) {
1679
+ return {
1680
+ description: definition.description ?? historicalProfiles.find(Boolean)?.description,
1681
+ id: definition.id,
1682
+ label: definition.label ?? historicalProfiles.find(Boolean)?.label,
1683
+ maxLiveP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxLiveP95Ms)),
1684
+ maxProviderP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxProviderP95Ms)),
1685
+ maxTurnP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxTurnP95Ms)),
1686
+ providers: aggregateProofTrendProviders(historicalProfiles.flatMap((profile) => profile.providers ?? [])),
1687
+ runtimeChannel: aggregateProofTrendRuntimeChannel(historicalProfiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined)),
1688
+ status: historicalProfiles.some((profile) => profile.status === "fail") ? "fail" : historicalProfiles.some((profile) => profile.status === "warn") ? "warn" : historicalProfiles.every((profile) => profile.status === "pass") ? "pass" : undefined
1689
+ };
1690
+ }
1691
+ const runtimeChannel = aggregateProofTrendRuntimeChannel(reports.map((report) => readProofTrendRuntimeChannel(report)).filter((channel) => Object.values(channel).some((value) => value !== undefined)));
1692
+ return {
1693
+ description: definition.description,
1694
+ id: definition.id,
1695
+ label: definition.label,
1696
+ maxLiveP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxLiveP95)), definition.liveOffsetMs, definition.maxLiveP95Ms ?? liveCap),
1697
+ maxProviderP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxProviderP95)), definition.providerOffsetMs, definition.maxProviderP95Ms ?? providerCap),
1698
+ maxTurnP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxTurnP95)), definition.turnOffsetMs, definition.maxTurnP95Ms ?? turnCap),
1699
+ providers: readProofTrendProviders(reports),
1700
+ runtimeChannel: runtimeChannel === undefined ? undefined : {
1701
+ maxBackpressureEvents: runtimeChannel.maxBackpressureEvents,
1702
+ maxFirstAudioLatencyMs: addProofTrendProfileOffset(runtimeChannel.maxFirstAudioLatencyMs, definition.runtimeOffsetMs, definition.maxRuntimeFirstAudioLatencyMs ?? runtimeFirstAudioCap),
1703
+ maxInterruptionP95Ms: addProofTrendProfileOffset(runtimeChannel.maxInterruptionP95Ms, Math.ceil((definition.runtimeOffsetMs ?? 0) / 2), definition.maxRuntimeInterruptionP95Ms ?? runtimeInterruptionCap),
1704
+ maxJitterMs: addProofTrendProfileOffset(runtimeChannel.maxJitterMs, Math.ceil((definition.runtimeOffsetMs ?? 0) / 4), definition.maxRuntimeJitterMs ?? runtimeJitterCap),
1705
+ maxTimestampDriftMs: addProofTrendProfileOffset(runtimeChannel.maxTimestampDriftMs, definition.runtimeOffsetMs, definition.maxRuntimeTimestampDriftMs ?? runtimeTimestampDriftCap),
1706
+ samples: runtimeChannel.samples,
1707
+ status: runtimeChannel.status
1708
+ },
1709
+ status: reports.some((report) => report.status === "fail" || !report.ok) ? "fail" : reports.some((report) => report.status === "warn") ? "warn" : reports.every((report) => report.ok) ? "pass" : undefined
1710
+ };
1711
+ });
1712
+ };
1590
1713
  var normalizeProviderStatus = (status) => status === "pass" ? "pass" : status === "fail" ? "fail" : "warn";
1591
1714
  var providerSortScore = (provider) => [
1592
1715
  recommendationStatusRank[provider.status],
@@ -1684,6 +1807,34 @@ var bestProviderByRole = (providers) => {
1684
1807
  return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
1685
1808
  };
1686
1809
  var formatProviderMix = (providers) => providers.length === 0 ? "n/a" : providers.map((provider) => provider.role && !(provider.label ?? provider.id).toLowerCase().startsWith(provider.role.toLowerCase()) ? `${provider.role.toUpperCase()} ${provider.label ?? provider.id}` : provider.label ?? provider.id).join(", ");
1810
+ var buildProfileRecommendations = (report, budgets) => (report.summary.profiles ?? []).map((profile) => {
1811
+ const providers = summarizeProofTrendProviders({
1812
+ ...report,
1813
+ cycles: [],
1814
+ summary: {
1815
+ cycles: report.summary.cycles,
1816
+ maxLiveP95Ms: profile.maxLiveP95Ms,
1817
+ maxProviderP95Ms: profile.maxProviderP95Ms,
1818
+ maxTurnP95Ms: profile.maxTurnP95Ms,
1819
+ providers: profile.providers,
1820
+ runtimeChannel: profile.runtimeChannel
1821
+ }
1822
+ }, budgets.maxProviderP95Ms);
1823
+ const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
1824
+ const hasRequiredProviderRoles = bestProviders.some((provider) => provider.role === "llm") && bestProviders.some((provider) => provider.role === "stt") && bestProviders.some((provider) => provider.role === "tts");
1825
+ const runtimePass = (profile.runtimeChannel?.status === undefined || profile.runtimeChannel.status === "pass") && (profile.runtimeChannel?.maxFirstAudioLatencyMs === undefined || profile.runtimeChannel.maxFirstAudioLatencyMs <= budgets.maxRuntimeFirstAudioLatencyMs) && (profile.runtimeChannel?.maxInterruptionP95Ms === undefined || profile.runtimeChannel.maxInterruptionP95Ms <= budgets.maxRuntimeInterruptionP95Ms) && (profile.runtimeChannel?.maxJitterMs === undefined || profile.runtimeChannel.maxJitterMs <= budgets.maxRuntimeJitterMs) && (profile.runtimeChannel?.maxTimestampDriftMs === undefined || profile.runtimeChannel.maxTimestampDriftMs <= budgets.maxRuntimeTimestampDriftMs) && (profile.runtimeChannel?.maxBackpressureEvents === undefined || profile.runtimeChannel.maxBackpressureEvents <= budgets.maxRuntimeBackpressureEvents);
1826
+ const latencyPass = (profile.maxProviderP95Ms === undefined || profile.maxProviderP95Ms <= budgets.maxProviderP95Ms) && (profile.maxLiveP95Ms === undefined || profile.maxLiveP95Ms <= budgets.maxLiveP95Ms) && (profile.maxTurnP95Ms === undefined || profile.maxTurnP95Ms <= budgets.maxTurnP95Ms);
1827
+ const status = profile.status === "fail" || !runtimePass ? "fail" : !latencyPass || !hasRequiredProviderRoles ? "warn" : "pass";
1828
+ return {
1829
+ bestProviders,
1830
+ id: profile.id,
1831
+ label: profile.label,
1832
+ nextMove: status === "pass" ? `Use this proven provider mix for ${profile.label ?? profile.id}: ${formatProviderMix(bestProviders)}.` : providers.length === 0 ? `Collect provider-specific sustained samples for ${profile.label ?? profile.id}.` : `Tune latency/runtime budgets for ${profile.label ?? profile.id} before promoting this profile.`,
1833
+ providerComparisonCount: providers.length,
1834
+ recommendation: status === "pass" ? `Profile ready: ${profile.label ?? profile.id}` : `Profile needs proof: ${profile.label ?? profile.id}`,
1835
+ status
1836
+ };
1837
+ });
1687
1838
  var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
1688
1839
  const issues = [];
1689
1840
  const requiredStatus = input.requireStatus ?? "pass";
@@ -1805,6 +1956,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
1805
1956
  const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
1806
1957
  const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
1807
1958
  const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
1959
+ const profileRecommendations = buildProfileRecommendations(report, budgets);
1808
1960
  const recommendations = [];
1809
1961
  const issues = [];
1810
1962
  if (report.ok !== true) {
@@ -1867,16 +2019,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
1867
2019
  surface: "turn-latency"
1868
2020
  });
1869
2021
  const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
2022
+ const profileStatus = worstRecommendationStatus(profileRecommendations.map((profile) => ({
2023
+ evidence: {},
2024
+ nextMove: profile.nextMove,
2025
+ recommendation: profile.recommendation,
2026
+ status: profile.status,
2027
+ surface: "provider-path"
2028
+ })));
2029
+ const combinedStatus = recommendationStatusRank[profileStatus] > recommendationStatusRank[status] ? profileStatus : status;
1870
2030
  return {
1871
2031
  bestProvider,
1872
2032
  bestProviders,
1873
2033
  generatedAt: new Date().toISOString(),
1874
2034
  issues,
1875
- ok: status !== "fail",
2035
+ ok: combinedStatus !== "fail",
2036
+ profiles: profileRecommendations,
1876
2037
  providers,
1877
2038
  recommendations,
1878
2039
  source: report.source || report.outputDir || report.runId || "proof-trends",
1879
- status,
2040
+ status: combinedStatus,
1880
2041
  summary: {
1881
2042
  keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
1882
2043
  keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
@@ -1907,6 +2068,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
1907
2068
  "| ---: | --- | --- | --- | ---: | ---: | --- |",
1908
2069
  ...report.providers.length ? report.providers.map((provider) => `| ${String(provider.rank)} | ${escapeMarkdown(provider.label ?? provider.id)} | ${escapeMarkdown(provider.role ?? "n/a")} | ${provider.status} | ${provider.p95Ms === undefined ? "n/a" : String(provider.p95Ms)} | ${provider.samples === undefined ? "n/a" : String(provider.samples)} | ${escapeMarkdown(provider.nextMove)} |`) : ["| n/a | n/a | n/a | n/a | n/a | n/a | No provider-specific samples were present. |"],
1909
2070
  "",
2071
+ "## Benchmark Profiles",
2072
+ "",
2073
+ "| Profile | Status | Provider mix | Next move |",
2074
+ "| --- | --- | --- | --- |",
2075
+ ...report.profiles.length ? report.profiles.map((profile) => `| ${escapeMarkdown(profile.label ?? profile.id)} | ${profile.status} | ${escapeMarkdown(formatProviderMix(profile.bestProviders))} | ${escapeMarkdown(profile.nextMove)} |`) : ["| n/a | n/a | n/a | No benchmark profiles were present. |"],
2076
+ "",
1910
2077
  "## Issues",
1911
2078
  "",
1912
2079
  ...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
@@ -1916,7 +2083,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
1916
2083
  const cards = report.recommendations.map((recommendation) => `<article class="${escapeHtml5(recommendation.status)}"><p class="eyebrow">${escapeHtml5(recommendation.surface)} \xB7 ${escapeHtml5(recommendation.status)}</p><h2>${escapeHtml5(recommendation.recommendation)}</h2><p>${escapeHtml5(recommendation.nextMove)}</p><pre>${escapeHtml5(JSON.stringify(recommendation.evidence, null, 2))}</pre></article>`).join("");
1917
2084
  const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
1918
2085
  const providerRows = report.providers.length === 0 ? "<li>No provider-specific samples were present.</li>" : report.providers.map((provider) => `<li><strong>#${String(provider.rank)} ${escapeHtml5(provider.label ?? provider.id)}</strong><span>${escapeHtml5(provider.role ?? "provider")} \xB7 ${escapeHtml5(provider.status)} \xB7 p95 ${escapeHtml5(provider.p95Ms ?? "n/a")}ms \xB7 ${escapeHtml5(provider.samples ?? "n/a")} sample(s)</span><small>${escapeHtml5(provider.nextMove)}</small></li>`).join("");
1919
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml5(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}li{margin:.45rem 0}li span,li small{display:block;color:#c9d3ca}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml5(title)}</h1><p>Generated ${escapeHtml5(report.generatedAt)} from ${escapeHtml5(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml5(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Best mix ${escapeHtml5(formatProviderMix(report.bestProviders))}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Provider Comparison</h2><ul>${providerRows}</ul></section><section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
2086
+ const profileRows = report.profiles.length === 0 ? "<li>No benchmark profiles were present.</li>" : report.profiles.map((profile) => `<li><strong>${escapeHtml5(profile.label ?? profile.id)}</strong><span>${escapeHtml5(profile.status)} \xB7 ${escapeHtml5(formatProviderMix(profile.bestProviders))}</span><small>${escapeHtml5(profile.nextMove)}</small></li>`).join("");
2087
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml5(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}li{margin:.45rem 0}li span,li small{display:block;color:#c9d3ca}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml5(title)}</h1><p>Generated ${escapeHtml5(report.generatedAt)} from ${escapeHtml5(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml5(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Best mix ${escapeHtml5(formatProviderMix(report.bestProviders))}</span><span class="pill">Profiles ${String(report.profiles.length)}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Benchmark Profiles</h2><ul>${profileRows}</ul></section><section class="hero"><h2>Provider Comparison</h2><ul>${providerRows}</ul></section><section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
1920
2088
  };
1921
2089
  var createVoiceProofTrendRecommendationRoutes = (options) => {
1922
2090
  const path = options.path ?? "/api/voice/proof-trend-recommendations";
package/dist/vue/index.js CHANGED
@@ -1416,6 +1416,40 @@ import { defineComponent as defineComponent5, h as h5 } from "vue";
1416
1416
  // src/proofTrends.ts
1417
1417
  import { Elysia } from "elysia";
1418
1418
  var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
1419
+ var DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS = [
1420
+ {
1421
+ description: "Browser recorder with longer passive listening and transcript capture.",
1422
+ id: "meeting-recorder",
1423
+ label: "Meeting recorder"
1424
+ },
1425
+ {
1426
+ description: "Realtime support agent with fast interruption recovery and tool-ready turns.",
1427
+ id: "support-agent",
1428
+ label: "Support agent",
1429
+ liveOffsetMs: 17,
1430
+ providerOffsetMs: 20,
1431
+ runtimeOffsetMs: 10,
1432
+ turnOffsetMs: 3
1433
+ },
1434
+ {
1435
+ description: "Appointment scheduler with short structured turns and reliable follow-up capture.",
1436
+ id: "appointment-scheduler",
1437
+ label: "Appointment scheduler",
1438
+ liveOffsetMs: 29,
1439
+ providerOffsetMs: 35,
1440
+ runtimeOffsetMs: 16,
1441
+ turnOffsetMs: 5
1442
+ },
1443
+ {
1444
+ description: "Noisy phone call with stricter transport and interruption proof requirements.",
1445
+ id: "noisy-phone-call",
1446
+ label: "Noisy phone call",
1447
+ liveOffsetMs: 40,
1448
+ providerOffsetMs: 60,
1449
+ runtimeOffsetMs: 22,
1450
+ turnOffsetMs: 7
1451
+ }
1452
+ ];
1419
1453
  var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
1420
1454
  var toTimeMs = (value) => {
1421
1455
  if (value instanceof Date) {
@@ -1508,6 +1542,95 @@ var readProofTrendRuntimeChannel = (report) => ({
1508
1542
  samples: report.summary.runtimeChannel?.samples ?? maxNumber(report.cycles.map((cycle) => cycle.runtimeChannel?.samples)),
1509
1543
  status: report.summary.runtimeChannel?.status
1510
1544
  });
1545
+ var addProofTrendProfileOffset = (value, offset, cap) => {
1546
+ if (value === undefined) {
1547
+ return;
1548
+ }
1549
+ const nextValue = Math.round(value + (offset ?? 0));
1550
+ return cap === undefined ? nextValue : Math.min(cap, nextValue);
1551
+ };
1552
+ var aggregateProofTrendProviders = (providers) => {
1553
+ const providersById = new Map;
1554
+ for (const provider of providers) {
1555
+ if (!provider.id) {
1556
+ continue;
1557
+ }
1558
+ const existing = providersById.get(provider.id);
1559
+ providersById.set(provider.id, {
1560
+ averageMs: maxNumber([existing?.averageMs, provider.averageMs]),
1561
+ id: provider.id,
1562
+ label: existing?.label ?? provider.label,
1563
+ p50Ms: maxNumber([existing?.p50Ms, provider.p50Ms]),
1564
+ p95Ms: maxNumber([existing?.p95Ms, provider.p95Ms]),
1565
+ role: existing?.role ?? provider.role,
1566
+ samples: (existing?.samples ?? 0) + (provider.samples ?? 0),
1567
+ status: existing?.status === "fail" || provider.status === "fail" ? "fail" : existing?.status === "warn" || provider.status === "warn" ? "warn" : provider.status ?? existing?.status
1568
+ });
1569
+ }
1570
+ return [...providersById.values()].sort((left, right) => (left.p95Ms ?? Number.POSITIVE_INFINITY) - (right.p95Ms ?? Number.POSITIVE_INFINITY));
1571
+ };
1572
+ var aggregateProofTrendRuntimeChannel = (channels) => {
1573
+ if (channels.length === 0) {
1574
+ return;
1575
+ }
1576
+ return {
1577
+ maxBackpressureEvents: maxNumber(channels.map((channel) => channel.maxBackpressureEvents)),
1578
+ maxFirstAudioLatencyMs: maxNumber(channels.map((channel) => channel.maxFirstAudioLatencyMs)),
1579
+ maxInterruptionP95Ms: maxNumber(channels.map((channel) => channel.maxInterruptionP95Ms)),
1580
+ maxJitterMs: maxNumber(channels.map((channel) => channel.maxJitterMs)),
1581
+ maxTimestampDriftMs: maxNumber(channels.map((channel) => channel.maxTimestampDriftMs)),
1582
+ samples: maxNumber(channels.map((channel) => channel.samples)),
1583
+ status: channels.some((channel) => channel.status === "fail") ? "fail" : channels.some((channel) => channel.status === "warn") ? "warn" : channels.every((channel) => channel.status === "pass") ? "pass" : undefined
1584
+ };
1585
+ };
1586
+ var readProofTrendProviders = (reports) => aggregateProofTrendProviders(reports.flatMap((report) => report.summary.providers && report.summary.providers.length > 0 ? report.summary.providers : report.cycles.flatMap((cycle) => cycle.providers ?? [])));
1587
+ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
1588
+ const reports = Array.isArray(input) ? input : [input];
1589
+ const definitions = options.profiles ?? DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS;
1590
+ const providerCap = options.maxProviderP95Ms ?? 1000;
1591
+ const liveCap = options.maxLiveP95Ms ?? 800;
1592
+ const turnCap = options.maxTurnP95Ms ?? 700;
1593
+ const runtimeFirstAudioCap = options.maxRuntimeFirstAudioLatencyMs ?? 600;
1594
+ const runtimeInterruptionCap = options.maxRuntimeInterruptionP95Ms ?? 300;
1595
+ const runtimeJitterCap = options.maxRuntimeJitterMs ?? 30;
1596
+ const runtimeTimestampDriftCap = options.maxRuntimeTimestampDriftMs ?? 800;
1597
+ return definitions.map((definition) => {
1598
+ const historicalProfiles = reports.flatMap((report) => report.summary.profiles?.filter((profile) => profile.id === definition.id) ?? []);
1599
+ if (historicalProfiles.length > 0) {
1600
+ return {
1601
+ description: definition.description ?? historicalProfiles.find(Boolean)?.description,
1602
+ id: definition.id,
1603
+ label: definition.label ?? historicalProfiles.find(Boolean)?.label,
1604
+ maxLiveP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxLiveP95Ms)),
1605
+ maxProviderP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxProviderP95Ms)),
1606
+ maxTurnP95Ms: maxNumber(historicalProfiles.map((profile) => profile.maxTurnP95Ms)),
1607
+ providers: aggregateProofTrendProviders(historicalProfiles.flatMap((profile) => profile.providers ?? [])),
1608
+ runtimeChannel: aggregateProofTrendRuntimeChannel(historicalProfiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined)),
1609
+ status: historicalProfiles.some((profile) => profile.status === "fail") ? "fail" : historicalProfiles.some((profile) => profile.status === "warn") ? "warn" : historicalProfiles.every((profile) => profile.status === "pass") ? "pass" : undefined
1610
+ };
1611
+ }
1612
+ const runtimeChannel = aggregateProofTrendRuntimeChannel(reports.map((report) => readProofTrendRuntimeChannel(report)).filter((channel) => Object.values(channel).some((value) => value !== undefined)));
1613
+ return {
1614
+ description: definition.description,
1615
+ id: definition.id,
1616
+ label: definition.label,
1617
+ maxLiveP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxLiveP95)), definition.liveOffsetMs, definition.maxLiveP95Ms ?? liveCap),
1618
+ maxProviderP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxProviderP95)), definition.providerOffsetMs, definition.maxProviderP95Ms ?? providerCap),
1619
+ maxTurnP95Ms: addProofTrendProfileOffset(maxNumber(reports.map(readProofTrendMaxTurnP95)), definition.turnOffsetMs, definition.maxTurnP95Ms ?? turnCap),
1620
+ providers: readProofTrendProviders(reports),
1621
+ runtimeChannel: runtimeChannel === undefined ? undefined : {
1622
+ maxBackpressureEvents: runtimeChannel.maxBackpressureEvents,
1623
+ maxFirstAudioLatencyMs: addProofTrendProfileOffset(runtimeChannel.maxFirstAudioLatencyMs, definition.runtimeOffsetMs, definition.maxRuntimeFirstAudioLatencyMs ?? runtimeFirstAudioCap),
1624
+ maxInterruptionP95Ms: addProofTrendProfileOffset(runtimeChannel.maxInterruptionP95Ms, Math.ceil((definition.runtimeOffsetMs ?? 0) / 2), definition.maxRuntimeInterruptionP95Ms ?? runtimeInterruptionCap),
1625
+ maxJitterMs: addProofTrendProfileOffset(runtimeChannel.maxJitterMs, Math.ceil((definition.runtimeOffsetMs ?? 0) / 4), definition.maxRuntimeJitterMs ?? runtimeJitterCap),
1626
+ maxTimestampDriftMs: addProofTrendProfileOffset(runtimeChannel.maxTimestampDriftMs, definition.runtimeOffsetMs, definition.maxRuntimeTimestampDriftMs ?? runtimeTimestampDriftCap),
1627
+ samples: runtimeChannel.samples,
1628
+ status: runtimeChannel.status
1629
+ },
1630
+ status: reports.some((report) => report.status === "fail" || !report.ok) ? "fail" : reports.some((report) => report.status === "warn") ? "warn" : reports.every((report) => report.ok) ? "pass" : undefined
1631
+ };
1632
+ });
1633
+ };
1511
1634
  var normalizeProviderStatus = (status) => status === "pass" ? "pass" : status === "fail" ? "fail" : "warn";
1512
1635
  var providerSortScore = (provider) => [
1513
1636
  recommendationStatusRank[provider.status],
@@ -1605,6 +1728,34 @@ var bestProviderByRole = (providers) => {
1605
1728
  return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
1606
1729
  };
1607
1730
  var formatProviderMix = (providers) => providers.length === 0 ? "n/a" : providers.map((provider) => provider.role && !(provider.label ?? provider.id).toLowerCase().startsWith(provider.role.toLowerCase()) ? `${provider.role.toUpperCase()} ${provider.label ?? provider.id}` : provider.label ?? provider.id).join(", ");
1731
+ var buildProfileRecommendations = (report, budgets) => (report.summary.profiles ?? []).map((profile) => {
1732
+ const providers = summarizeProofTrendProviders({
1733
+ ...report,
1734
+ cycles: [],
1735
+ summary: {
1736
+ cycles: report.summary.cycles,
1737
+ maxLiveP95Ms: profile.maxLiveP95Ms,
1738
+ maxProviderP95Ms: profile.maxProviderP95Ms,
1739
+ maxTurnP95Ms: profile.maxTurnP95Ms,
1740
+ providers: profile.providers,
1741
+ runtimeChannel: profile.runtimeChannel
1742
+ }
1743
+ }, budgets.maxProviderP95Ms);
1744
+ const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
1745
+ const hasRequiredProviderRoles = bestProviders.some((provider) => provider.role === "llm") && bestProviders.some((provider) => provider.role === "stt") && bestProviders.some((provider) => provider.role === "tts");
1746
+ const runtimePass = (profile.runtimeChannel?.status === undefined || profile.runtimeChannel.status === "pass") && (profile.runtimeChannel?.maxFirstAudioLatencyMs === undefined || profile.runtimeChannel.maxFirstAudioLatencyMs <= budgets.maxRuntimeFirstAudioLatencyMs) && (profile.runtimeChannel?.maxInterruptionP95Ms === undefined || profile.runtimeChannel.maxInterruptionP95Ms <= budgets.maxRuntimeInterruptionP95Ms) && (profile.runtimeChannel?.maxJitterMs === undefined || profile.runtimeChannel.maxJitterMs <= budgets.maxRuntimeJitterMs) && (profile.runtimeChannel?.maxTimestampDriftMs === undefined || profile.runtimeChannel.maxTimestampDriftMs <= budgets.maxRuntimeTimestampDriftMs) && (profile.runtimeChannel?.maxBackpressureEvents === undefined || profile.runtimeChannel.maxBackpressureEvents <= budgets.maxRuntimeBackpressureEvents);
1747
+ const latencyPass = (profile.maxProviderP95Ms === undefined || profile.maxProviderP95Ms <= budgets.maxProviderP95Ms) && (profile.maxLiveP95Ms === undefined || profile.maxLiveP95Ms <= budgets.maxLiveP95Ms) && (profile.maxTurnP95Ms === undefined || profile.maxTurnP95Ms <= budgets.maxTurnP95Ms);
1748
+ const status = profile.status === "fail" || !runtimePass ? "fail" : !latencyPass || !hasRequiredProviderRoles ? "warn" : "pass";
1749
+ return {
1750
+ bestProviders,
1751
+ id: profile.id,
1752
+ label: profile.label,
1753
+ nextMove: status === "pass" ? `Use this proven provider mix for ${profile.label ?? profile.id}: ${formatProviderMix(bestProviders)}.` : providers.length === 0 ? `Collect provider-specific sustained samples for ${profile.label ?? profile.id}.` : `Tune latency/runtime budgets for ${profile.label ?? profile.id} before promoting this profile.`,
1754
+ providerComparisonCount: providers.length,
1755
+ recommendation: status === "pass" ? `Profile ready: ${profile.label ?? profile.id}` : `Profile needs proof: ${profile.label ?? profile.id}`,
1756
+ status
1757
+ };
1758
+ });
1608
1759
  var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
1609
1760
  const issues = [];
1610
1761
  const requiredStatus = input.requireStatus ?? "pass";
@@ -1726,6 +1877,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
1726
1877
  const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
1727
1878
  const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
1728
1879
  const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
1880
+ const profileRecommendations = buildProfileRecommendations(report, budgets);
1729
1881
  const recommendations = [];
1730
1882
  const issues = [];
1731
1883
  if (report.ok !== true) {
@@ -1788,16 +1940,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
1788
1940
  surface: "turn-latency"
1789
1941
  });
1790
1942
  const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
1943
+ const profileStatus = worstRecommendationStatus(profileRecommendations.map((profile) => ({
1944
+ evidence: {},
1945
+ nextMove: profile.nextMove,
1946
+ recommendation: profile.recommendation,
1947
+ status: profile.status,
1948
+ surface: "provider-path"
1949
+ })));
1950
+ const combinedStatus = recommendationStatusRank[profileStatus] > recommendationStatusRank[status] ? profileStatus : status;
1791
1951
  return {
1792
1952
  bestProvider,
1793
1953
  bestProviders,
1794
1954
  generatedAt: new Date().toISOString(),
1795
1955
  issues,
1796
- ok: status !== "fail",
1956
+ ok: combinedStatus !== "fail",
1957
+ profiles: profileRecommendations,
1797
1958
  providers,
1798
1959
  recommendations,
1799
1960
  source: report.source || report.outputDir || report.runId || "proof-trends",
1800
- status,
1961
+ status: combinedStatus,
1801
1962
  summary: {
1802
1963
  keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
1803
1964
  keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
@@ -1828,6 +1989,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
1828
1989
  "| ---: | --- | --- | --- | ---: | ---: | --- |",
1829
1990
  ...report.providers.length ? report.providers.map((provider) => `| ${String(provider.rank)} | ${escapeMarkdown(provider.label ?? provider.id)} | ${escapeMarkdown(provider.role ?? "n/a")} | ${provider.status} | ${provider.p95Ms === undefined ? "n/a" : String(provider.p95Ms)} | ${provider.samples === undefined ? "n/a" : String(provider.samples)} | ${escapeMarkdown(provider.nextMove)} |`) : ["| n/a | n/a | n/a | n/a | n/a | n/a | No provider-specific samples were present. |"],
1830
1991
  "",
1992
+ "## Benchmark Profiles",
1993
+ "",
1994
+ "| Profile | Status | Provider mix | Next move |",
1995
+ "| --- | --- | --- | --- |",
1996
+ ...report.profiles.length ? report.profiles.map((profile) => `| ${escapeMarkdown(profile.label ?? profile.id)} | ${profile.status} | ${escapeMarkdown(formatProviderMix(profile.bestProviders))} | ${escapeMarkdown(profile.nextMove)} |`) : ["| n/a | n/a | n/a | No benchmark profiles were present. |"],
1997
+ "",
1831
1998
  "## Issues",
1832
1999
  "",
1833
2000
  ...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
@@ -1837,7 +2004,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
1837
2004
  const cards = report.recommendations.map((recommendation) => `<article class="${escapeHtml5(recommendation.status)}"><p class="eyebrow">${escapeHtml5(recommendation.surface)} \xB7 ${escapeHtml5(recommendation.status)}</p><h2>${escapeHtml5(recommendation.recommendation)}</h2><p>${escapeHtml5(recommendation.nextMove)}</p><pre>${escapeHtml5(JSON.stringify(recommendation.evidence, null, 2))}</pre></article>`).join("");
1838
2005
  const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
1839
2006
  const providerRows = report.providers.length === 0 ? "<li>No provider-specific samples were present.</li>" : report.providers.map((provider) => `<li><strong>#${String(provider.rank)} ${escapeHtml5(provider.label ?? provider.id)}</strong><span>${escapeHtml5(provider.role ?? "provider")} \xB7 ${escapeHtml5(provider.status)} \xB7 p95 ${escapeHtml5(provider.p95Ms ?? "n/a")}ms \xB7 ${escapeHtml5(provider.samples ?? "n/a")} sample(s)</span><small>${escapeHtml5(provider.nextMove)}</small></li>`).join("");
1840
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml5(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}li{margin:.45rem 0}li span,li small{display:block;color:#c9d3ca}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml5(title)}</h1><p>Generated ${escapeHtml5(report.generatedAt)} from ${escapeHtml5(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml5(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Best mix ${escapeHtml5(formatProviderMix(report.bestProviders))}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Provider Comparison</h2><ul>${providerRows}</ul></section><section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
2007
+ const profileRows = report.profiles.length === 0 ? "<li>No benchmark profiles were present.</li>" : report.profiles.map((profile) => `<li><strong>${escapeHtml5(profile.label ?? profile.id)}</strong><span>${escapeHtml5(profile.status)} \xB7 ${escapeHtml5(formatProviderMix(profile.bestProviders))}</span><small>${escapeHtml5(profile.nextMove)}</small></li>`).join("");
2008
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml5(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}li{margin:.45rem 0}li span,li small{display:block;color:#c9d3ca}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml5(title)}</h1><p>Generated ${escapeHtml5(report.generatedAt)} from ${escapeHtml5(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml5(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Best mix ${escapeHtml5(formatProviderMix(report.bestProviders))}</span><span class="pill">Profiles ${String(report.profiles.length)}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Benchmark Profiles</h2><ul>${profileRows}</ul></section><section class="hero"><h2>Provider Comparison</h2><ul>${providerRows}</ul></section><section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
1841
2009
  };
1842
2010
  var createVoiceProofTrendRecommendationRoutes = (options) => {
1843
2011
  const path = options.path ?? "/api/voice/proof-trend-recommendations";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.337",
3
+ "version": "0.0.22-beta.339",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",