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

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.
@@ -3936,6 +3936,34 @@ var bestProviderByRole = (providers) => {
3936
3936
  return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
3937
3937
  };
3938
3938
  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(", ");
3939
+ var buildProfileRecommendations = (report, budgets) => (report.summary.profiles ?? []).map((profile) => {
3940
+ const providers = summarizeProofTrendProviders({
3941
+ ...report,
3942
+ cycles: [],
3943
+ summary: {
3944
+ cycles: report.summary.cycles,
3945
+ maxLiveP95Ms: profile.maxLiveP95Ms,
3946
+ maxProviderP95Ms: profile.maxProviderP95Ms,
3947
+ maxTurnP95Ms: profile.maxTurnP95Ms,
3948
+ providers: profile.providers,
3949
+ runtimeChannel: profile.runtimeChannel
3950
+ }
3951
+ }, budgets.maxProviderP95Ms);
3952
+ const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
3953
+ const hasRequiredProviderRoles = bestProviders.some((provider) => provider.role === "llm") && bestProviders.some((provider) => provider.role === "stt") && bestProviders.some((provider) => provider.role === "tts");
3954
+ 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);
3955
+ const latencyPass = (profile.maxProviderP95Ms === undefined || profile.maxProviderP95Ms <= budgets.maxProviderP95Ms) && (profile.maxLiveP95Ms === undefined || profile.maxLiveP95Ms <= budgets.maxLiveP95Ms) && (profile.maxTurnP95Ms === undefined || profile.maxTurnP95Ms <= budgets.maxTurnP95Ms);
3956
+ const status = profile.status === "fail" || !runtimePass ? "fail" : !latencyPass || !hasRequiredProviderRoles ? "warn" : "pass";
3957
+ return {
3958
+ bestProviders,
3959
+ id: profile.id,
3960
+ label: profile.label,
3961
+ 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.`,
3962
+ providerComparisonCount: providers.length,
3963
+ recommendation: status === "pass" ? `Profile ready: ${profile.label ?? profile.id}` : `Profile needs proof: ${profile.label ?? profile.id}`,
3964
+ status
3965
+ };
3966
+ });
3939
3967
  var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
3940
3968
  const issues = [];
3941
3969
  const requiredStatus = input.requireStatus ?? "pass";
@@ -4057,6 +4085,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
4057
4085
  const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
4058
4086
  const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
4059
4087
  const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
4088
+ const profileRecommendations = buildProfileRecommendations(report, budgets);
4060
4089
  const recommendations = [];
4061
4090
  const issues = [];
4062
4091
  if (report.ok !== true) {
@@ -4119,16 +4148,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
4119
4148
  surface: "turn-latency"
4120
4149
  });
4121
4150
  const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
4151
+ const profileStatus = worstRecommendationStatus(profileRecommendations.map((profile) => ({
4152
+ evidence: {},
4153
+ nextMove: profile.nextMove,
4154
+ recommendation: profile.recommendation,
4155
+ status: profile.status,
4156
+ surface: "provider-path"
4157
+ })));
4158
+ const combinedStatus = recommendationStatusRank[profileStatus] > recommendationStatusRank[status] ? profileStatus : status;
4122
4159
  return {
4123
4160
  bestProvider,
4124
4161
  bestProviders,
4125
4162
  generatedAt: new Date().toISOString(),
4126
4163
  issues,
4127
- ok: status !== "fail",
4164
+ ok: combinedStatus !== "fail",
4165
+ profiles: profileRecommendations,
4128
4166
  providers,
4129
4167
  recommendations,
4130
4168
  source: report.source || report.outputDir || report.runId || "proof-trends",
4131
- status,
4169
+ status: combinedStatus,
4132
4170
  summary: {
4133
4171
  keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
4134
4172
  keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
@@ -4159,6 +4197,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
4159
4197
  "| ---: | --- | --- | --- | ---: | ---: | --- |",
4160
4198
  ...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
4199
  "",
4200
+ "## Benchmark Profiles",
4201
+ "",
4202
+ "| Profile | Status | Provider mix | Next move |",
4203
+ "| --- | --- | --- | --- |",
4204
+ ...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. |"],
4205
+ "",
4162
4206
  "## Issues",
4163
4207
  "",
4164
4208
  ...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
@@ -4168,7 +4212,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
4168
4212
  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
4213
  const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml3(issue)}</li>`).join("");
4170
4214
  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>`;
4215
+ 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("");
4216
+ 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
4217
  };
4173
4218
  var createVoiceProofTrendRecommendationRoutes = (options) => {
4174
4219
  const path = options.path ?? "/api/voice/proof-trend-recommendations";
package/dist/index.d.ts CHANGED
@@ -31,7 +31,7 @@ export type { VoicePlatformCoverageAssertionInput, VoicePlatformCoverageAssertio
31
31
  export { assertVoiceProofTrendEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReport, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, 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, VoiceProofTrendProfileRecommendation, 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
@@ -14653,6 +14653,34 @@ var bestProviderByRole = (providers) => {
14653
14653
  return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
14654
14654
  };
14655
14655
  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(", ");
14656
+ var buildProfileRecommendations = (report, budgets) => (report.summary.profiles ?? []).map((profile) => {
14657
+ const providers = summarizeProofTrendProviders({
14658
+ ...report,
14659
+ cycles: [],
14660
+ summary: {
14661
+ cycles: report.summary.cycles,
14662
+ maxLiveP95Ms: profile.maxLiveP95Ms,
14663
+ maxProviderP95Ms: profile.maxProviderP95Ms,
14664
+ maxTurnP95Ms: profile.maxTurnP95Ms,
14665
+ providers: profile.providers,
14666
+ runtimeChannel: profile.runtimeChannel
14667
+ }
14668
+ }, budgets.maxProviderP95Ms);
14669
+ const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
14670
+ const hasRequiredProviderRoles = bestProviders.some((provider) => provider.role === "llm") && bestProviders.some((provider) => provider.role === "stt") && bestProviders.some((provider) => provider.role === "tts");
14671
+ 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);
14672
+ const latencyPass = (profile.maxProviderP95Ms === undefined || profile.maxProviderP95Ms <= budgets.maxProviderP95Ms) && (profile.maxLiveP95Ms === undefined || profile.maxLiveP95Ms <= budgets.maxLiveP95Ms) && (profile.maxTurnP95Ms === undefined || profile.maxTurnP95Ms <= budgets.maxTurnP95Ms);
14673
+ const status = profile.status === "fail" || !runtimePass ? "fail" : !latencyPass || !hasRequiredProviderRoles ? "warn" : "pass";
14674
+ return {
14675
+ bestProviders,
14676
+ id: profile.id,
14677
+ label: profile.label,
14678
+ 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.`,
14679
+ providerComparisonCount: providers.length,
14680
+ recommendation: status === "pass" ? `Profile ready: ${profile.label ?? profile.id}` : `Profile needs proof: ${profile.label ?? profile.id}`,
14681
+ status
14682
+ };
14683
+ });
14656
14684
  var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
14657
14685
  const issues = [];
14658
14686
  const requiredStatus = input.requireStatus ?? "pass";
@@ -14774,6 +14802,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
14774
14802
  const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
14775
14803
  const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
14776
14804
  const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
14805
+ const profileRecommendations = buildProfileRecommendations(report, budgets);
14777
14806
  const recommendations = [];
14778
14807
  const issues = [];
14779
14808
  if (report.ok !== true) {
@@ -14836,16 +14865,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
14836
14865
  surface: "turn-latency"
14837
14866
  });
14838
14867
  const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
14868
+ const profileStatus = worstRecommendationStatus(profileRecommendations.map((profile) => ({
14869
+ evidence: {},
14870
+ nextMove: profile.nextMove,
14871
+ recommendation: profile.recommendation,
14872
+ status: profile.status,
14873
+ surface: "provider-path"
14874
+ })));
14875
+ const combinedStatus = recommendationStatusRank[profileStatus] > recommendationStatusRank[status] ? profileStatus : status;
14839
14876
  return {
14840
14877
  bestProvider,
14841
14878
  bestProviders,
14842
14879
  generatedAt: new Date().toISOString(),
14843
14880
  issues,
14844
- ok: status !== "fail",
14881
+ ok: combinedStatus !== "fail",
14882
+ profiles: profileRecommendations,
14845
14883
  providers,
14846
14884
  recommendations,
14847
14885
  source: report.source || report.outputDir || report.runId || "proof-trends",
14848
- status,
14886
+ status: combinedStatus,
14849
14887
  summary: {
14850
14888
  keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
14851
14889
  keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
@@ -14876,6 +14914,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
14876
14914
  "| ---: | --- | --- | --- | ---: | ---: | --- |",
14877
14915
  ...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
14916
  "",
14917
+ "## Benchmark Profiles",
14918
+ "",
14919
+ "| Profile | Status | Provider mix | Next move |",
14920
+ "| --- | --- | --- | --- |",
14921
+ ...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. |"],
14922
+ "",
14879
14923
  "## Issues",
14880
14924
  "",
14881
14925
  ...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
@@ -14885,7 +14929,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
14885
14929
  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
14930
  const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml22(issue)}</li>`).join("");
14887
14931
  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>`;
14932
+ 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("");
14933
+ 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
14934
  };
14890
14935
  var createVoiceProofTrendRecommendationRoutes = (options) => {
14891
14936
  const path = options.path ?? "/api/voice/proof-trend-recommendations";
@@ -4,10 +4,22 @@ 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
+ };
11
23
  export type VoiceProofTrendProviderSummary = {
12
24
  averageMs?: number;
13
25
  id: string;
@@ -149,6 +161,7 @@ export type VoiceProofTrendRecommendationReport = {
149
161
  generatedAt: string;
150
162
  issues: string[];
151
163
  ok: boolean;
164
+ profiles: VoiceProofTrendProfileRecommendation[];
152
165
  providers: VoiceProofTrendProviderRecommendation[];
153
166
  recommendations: VoiceProofTrendRecommendation[];
154
167
  source: string;
@@ -161,6 +174,15 @@ export type VoiceProofTrendRecommendationReport = {
161
174
  switchRecommended: boolean;
162
175
  };
163
176
  };
177
+ export type VoiceProofTrendProfileRecommendation = {
178
+ bestProviders: VoiceProofTrendProviderRecommendation[];
179
+ id: string;
180
+ label?: string;
181
+ nextMove: string;
182
+ providerComparisonCount: number;
183
+ recommendation: string;
184
+ status: VoiceProofTrendRecommendationStatus;
185
+ };
164
186
  export type VoiceProofTrendRecommendationOptions = {
165
187
  currentProviderId?: string;
166
188
  maxLiveP95Ms?: number;
@@ -1684,6 +1684,34 @@ var bestProviderByRole = (providers) => {
1684
1684
  return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
1685
1685
  };
1686
1686
  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(", ");
1687
+ var buildProfileRecommendations = (report, budgets) => (report.summary.profiles ?? []).map((profile) => {
1688
+ const providers = summarizeProofTrendProviders({
1689
+ ...report,
1690
+ cycles: [],
1691
+ summary: {
1692
+ cycles: report.summary.cycles,
1693
+ maxLiveP95Ms: profile.maxLiveP95Ms,
1694
+ maxProviderP95Ms: profile.maxProviderP95Ms,
1695
+ maxTurnP95Ms: profile.maxTurnP95Ms,
1696
+ providers: profile.providers,
1697
+ runtimeChannel: profile.runtimeChannel
1698
+ }
1699
+ }, budgets.maxProviderP95Ms);
1700
+ const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
1701
+ const hasRequiredProviderRoles = bestProviders.some((provider) => provider.role === "llm") && bestProviders.some((provider) => provider.role === "stt") && bestProviders.some((provider) => provider.role === "tts");
1702
+ 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);
1703
+ const latencyPass = (profile.maxProviderP95Ms === undefined || profile.maxProviderP95Ms <= budgets.maxProviderP95Ms) && (profile.maxLiveP95Ms === undefined || profile.maxLiveP95Ms <= budgets.maxLiveP95Ms) && (profile.maxTurnP95Ms === undefined || profile.maxTurnP95Ms <= budgets.maxTurnP95Ms);
1704
+ const status = profile.status === "fail" || !runtimePass ? "fail" : !latencyPass || !hasRequiredProviderRoles ? "warn" : "pass";
1705
+ return {
1706
+ bestProviders,
1707
+ id: profile.id,
1708
+ label: profile.label,
1709
+ 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.`,
1710
+ providerComparisonCount: providers.length,
1711
+ recommendation: status === "pass" ? `Profile ready: ${profile.label ?? profile.id}` : `Profile needs proof: ${profile.label ?? profile.id}`,
1712
+ status
1713
+ };
1714
+ });
1687
1715
  var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
1688
1716
  const issues = [];
1689
1717
  const requiredStatus = input.requireStatus ?? "pass";
@@ -1805,6 +1833,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
1805
1833
  const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
1806
1834
  const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
1807
1835
  const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
1836
+ const profileRecommendations = buildProfileRecommendations(report, budgets);
1808
1837
  const recommendations = [];
1809
1838
  const issues = [];
1810
1839
  if (report.ok !== true) {
@@ -1867,16 +1896,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
1867
1896
  surface: "turn-latency"
1868
1897
  });
1869
1898
  const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
1899
+ const profileStatus = worstRecommendationStatus(profileRecommendations.map((profile) => ({
1900
+ evidence: {},
1901
+ nextMove: profile.nextMove,
1902
+ recommendation: profile.recommendation,
1903
+ status: profile.status,
1904
+ surface: "provider-path"
1905
+ })));
1906
+ const combinedStatus = recommendationStatusRank[profileStatus] > recommendationStatusRank[status] ? profileStatus : status;
1870
1907
  return {
1871
1908
  bestProvider,
1872
1909
  bestProviders,
1873
1910
  generatedAt: new Date().toISOString(),
1874
1911
  issues,
1875
- ok: status !== "fail",
1912
+ ok: combinedStatus !== "fail",
1913
+ profiles: profileRecommendations,
1876
1914
  providers,
1877
1915
  recommendations,
1878
1916
  source: report.source || report.outputDir || report.runId || "proof-trends",
1879
- status,
1917
+ status: combinedStatus,
1880
1918
  summary: {
1881
1919
  keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
1882
1920
  keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
@@ -1907,6 +1945,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
1907
1945
  "| ---: | --- | --- | --- | ---: | ---: | --- |",
1908
1946
  ...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
1947
  "",
1948
+ "## Benchmark Profiles",
1949
+ "",
1950
+ "| Profile | Status | Provider mix | Next move |",
1951
+ "| --- | --- | --- | --- |",
1952
+ ...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. |"],
1953
+ "",
1910
1954
  "## Issues",
1911
1955
  "",
1912
1956
  ...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
@@ -1916,7 +1960,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
1916
1960
  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
1961
  const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
1918
1962
  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>`;
1963
+ 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("");
1964
+ 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
1965
  };
1921
1966
  var createVoiceProofTrendRecommendationRoutes = (options) => {
1922
1967
  const path = options.path ?? "/api/voice/proof-trend-recommendations";
package/dist/vue/index.js CHANGED
@@ -1605,6 +1605,34 @@ var bestProviderByRole = (providers) => {
1605
1605
  return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
1606
1606
  };
1607
1607
  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(", ");
1608
+ var buildProfileRecommendations = (report, budgets) => (report.summary.profiles ?? []).map((profile) => {
1609
+ const providers = summarizeProofTrendProviders({
1610
+ ...report,
1611
+ cycles: [],
1612
+ summary: {
1613
+ cycles: report.summary.cycles,
1614
+ maxLiveP95Ms: profile.maxLiveP95Ms,
1615
+ maxProviderP95Ms: profile.maxProviderP95Ms,
1616
+ maxTurnP95Ms: profile.maxTurnP95Ms,
1617
+ providers: profile.providers,
1618
+ runtimeChannel: profile.runtimeChannel
1619
+ }
1620
+ }, budgets.maxProviderP95Ms);
1621
+ const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
1622
+ const hasRequiredProviderRoles = bestProviders.some((provider) => provider.role === "llm") && bestProviders.some((provider) => provider.role === "stt") && bestProviders.some((provider) => provider.role === "tts");
1623
+ 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);
1624
+ const latencyPass = (profile.maxProviderP95Ms === undefined || profile.maxProviderP95Ms <= budgets.maxProviderP95Ms) && (profile.maxLiveP95Ms === undefined || profile.maxLiveP95Ms <= budgets.maxLiveP95Ms) && (profile.maxTurnP95Ms === undefined || profile.maxTurnP95Ms <= budgets.maxTurnP95Ms);
1625
+ const status = profile.status === "fail" || !runtimePass ? "fail" : !latencyPass || !hasRequiredProviderRoles ? "warn" : "pass";
1626
+ return {
1627
+ bestProviders,
1628
+ id: profile.id,
1629
+ label: profile.label,
1630
+ 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.`,
1631
+ providerComparisonCount: providers.length,
1632
+ recommendation: status === "pass" ? `Profile ready: ${profile.label ?? profile.id}` : `Profile needs proof: ${profile.label ?? profile.id}`,
1633
+ status
1634
+ };
1635
+ });
1608
1636
  var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
1609
1637
  const issues = [];
1610
1638
  const requiredStatus = input.requireStatus ?? "pass";
@@ -1726,6 +1754,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
1726
1754
  const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
1727
1755
  const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
1728
1756
  const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
1757
+ const profileRecommendations = buildProfileRecommendations(report, budgets);
1729
1758
  const recommendations = [];
1730
1759
  const issues = [];
1731
1760
  if (report.ok !== true) {
@@ -1788,16 +1817,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
1788
1817
  surface: "turn-latency"
1789
1818
  });
1790
1819
  const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
1820
+ const profileStatus = worstRecommendationStatus(profileRecommendations.map((profile) => ({
1821
+ evidence: {},
1822
+ nextMove: profile.nextMove,
1823
+ recommendation: profile.recommendation,
1824
+ status: profile.status,
1825
+ surface: "provider-path"
1826
+ })));
1827
+ const combinedStatus = recommendationStatusRank[profileStatus] > recommendationStatusRank[status] ? profileStatus : status;
1791
1828
  return {
1792
1829
  bestProvider,
1793
1830
  bestProviders,
1794
1831
  generatedAt: new Date().toISOString(),
1795
1832
  issues,
1796
- ok: status !== "fail",
1833
+ ok: combinedStatus !== "fail",
1834
+ profiles: profileRecommendations,
1797
1835
  providers,
1798
1836
  recommendations,
1799
1837
  source: report.source || report.outputDir || report.runId || "proof-trends",
1800
- status,
1838
+ status: combinedStatus,
1801
1839
  summary: {
1802
1840
  keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
1803
1841
  keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
@@ -1828,6 +1866,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
1828
1866
  "| ---: | --- | --- | --- | ---: | ---: | --- |",
1829
1867
  ...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
1868
  "",
1869
+ "## Benchmark Profiles",
1870
+ "",
1871
+ "| Profile | Status | Provider mix | Next move |",
1872
+ "| --- | --- | --- | --- |",
1873
+ ...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. |"],
1874
+ "",
1831
1875
  "## Issues",
1832
1876
  "",
1833
1877
  ...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
@@ -1837,7 +1881,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
1837
1881
  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
1882
  const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
1839
1883
  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>`;
1884
+ 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("");
1885
+ 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
1886
  };
1842
1887
  var createVoiceProofTrendRecommendationRoutes = (options) => {
1843
1888
  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.338",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",