@absolutejs/voice 0.0.22-beta.335 → 0.0.22-beta.337
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.js +27 -10
- package/dist/index.js +27 -10
- package/dist/proofTrends.d.ts +1 -0
- package/dist/react/index.js +27 -10
- package/dist/vue/index.js +27 -10
- package/package.json +1 -1
package/dist/client/index.js
CHANGED
|
@@ -3924,6 +3924,18 @@ var shouldSwitchProvider = (current, best, options) => {
|
|
|
3924
3924
|
const improvementRatio = current.p95Ms > 0 ? improvementMs / current.p95Ms : 0;
|
|
3925
3925
|
return improvementMs >= minImprovementMs || improvementRatio >= minImprovementRatio;
|
|
3926
3926
|
};
|
|
3927
|
+
var bestProviderByRole = (providers) => {
|
|
3928
|
+
const best = new Map;
|
|
3929
|
+
for (const provider of providers) {
|
|
3930
|
+
const role = provider.role ?? provider.id;
|
|
3931
|
+
const existing = best.get(role);
|
|
3932
|
+
if (!existing || compareProviders(provider, existing) < 0) {
|
|
3933
|
+
best.set(role, provider);
|
|
3934
|
+
}
|
|
3935
|
+
}
|
|
3936
|
+
return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
|
|
3937
|
+
};
|
|
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(", ");
|
|
3927
3939
|
var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
|
|
3928
3940
|
const issues = [];
|
|
3929
3941
|
const requiredStatus = input.requireStatus ?? "pass";
|
|
@@ -4040,8 +4052,11 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
4040
4052
|
const runtimeChannel = readProofTrendRuntimeChannel(report);
|
|
4041
4053
|
const providers = summarizeProofTrendProviders(report, budgets.maxProviderP95Ms);
|
|
4042
4054
|
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
4055
|
+
const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
|
|
4043
4056
|
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
4044
|
-
const
|
|
4057
|
+
const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
|
|
4058
|
+
const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
|
|
4059
|
+
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
|
|
4045
4060
|
const recommendations = [];
|
|
4046
4061
|
const issues = [];
|
|
4047
4062
|
if (report.ok !== true) {
|
|
@@ -4049,19 +4064,20 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
4049
4064
|
}
|
|
4050
4065
|
recommendations.push({
|
|
4051
4066
|
evidence: {
|
|
4052
|
-
bestProviderId: bestProvider?.id,
|
|
4053
|
-
|
|
4067
|
+
bestProviderId: currentProvider || hasSingleProviderRole ? bestComparableProvider?.id ?? bestProvider?.id : undefined,
|
|
4068
|
+
bestProviderMix: formatProviderMix(bestProviders),
|
|
4069
|
+
bestProviderP95Ms: currentProvider || hasSingleProviderRole ? bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms : undefined,
|
|
4054
4070
|
budgetMs: budgets.maxProviderP95Ms,
|
|
4055
4071
|
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
4056
4072
|
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
4057
4073
|
providerComparisonCount: providers.length,
|
|
4058
4074
|
providerP95Ms: maxProviderP95Ms
|
|
4059
4075
|
},
|
|
4060
|
-
nextMove: providers.length > 0 ? providerSwitchRecommended ? `Route latency-sensitive
|
|
4061
|
-
providerId:
|
|
4062
|
-
recommendation: providers.length > 0 ? providerSwitchRecommended ? `Switch latency-sensitive routing to ${
|
|
4063
|
-
role:
|
|
4064
|
-
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
4076
|
+
nextMove: providers.length > 0 ? providerSwitchRecommended ? `Route latency-sensitive ${currentProvider?.role ?? "provider"} traffic to ${bestComparableProvider?.label ?? bestComparableProvider?.id} for this call profile and keep the current path as fallback.` : bestProviders.length > 0 ? `Use the fastest proven provider mix for this call profile: ${formatProviderMix(bestProviders)}.` : "Collect provider-specific sustained samples before making provider-specific routing decisions." : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep the current provider route for latency-sensitive turns and keep collecting sustained proof." : "Route latency-sensitive turns to a faster provider profile or tighten fallback/circuit-breaker budgets before promotion.",
|
|
4077
|
+
providerId: providerSwitchRecommended ? bestComparableProvider?.id : bestProviders.length === 1 ? bestProviders[0]?.id : undefined,
|
|
4078
|
+
recommendation: providers.length > 0 ? providerSwitchRecommended ? `Switch latency-sensitive ${currentProvider?.role ?? "provider"} routing to ${bestComparableProvider?.label ?? bestComparableProvider?.id}` : bestProviders.length > 0 ? "Prefer the fastest proven provider mix for this call profile" : "Collect provider-specific latency samples" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep current provider path" : "Change provider routing for latency-sensitive traffic",
|
|
4079
|
+
role: currentProvider || hasSingleProviderRole ? bestComparableProvider?.role : undefined,
|
|
4080
|
+
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProviders.length > 0 ? "pass" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
4065
4081
|
surface: "provider-path"
|
|
4066
4082
|
});
|
|
4067
4083
|
const runtimePass = withinBudget(runtimeChannel.maxFirstAudioLatencyMs, budgets.maxRuntimeFirstAudioLatencyMs) && withinBudget(runtimeChannel.maxInterruptionP95Ms, budgets.maxRuntimeInterruptionP95Ms) && withinBudget(runtimeChannel.maxJitterMs, budgets.maxRuntimeJitterMs) && withinBudget(runtimeChannel.maxTimestampDriftMs, budgets.maxRuntimeTimestampDriftMs) && withinBudget(runtimeChannel.maxBackpressureEvents, budgets.maxRuntimeBackpressureEvents);
|
|
@@ -4105,6 +4121,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
4105
4121
|
const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
|
|
4106
4122
|
return {
|
|
4107
4123
|
bestProvider,
|
|
4124
|
+
bestProviders,
|
|
4108
4125
|
generatedAt: new Date().toISOString(),
|
|
4109
4126
|
issues,
|
|
4110
4127
|
ok: status !== "fail",
|
|
@@ -4128,7 +4145,7 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
|
|
|
4128
4145
|
"",
|
|
4129
4146
|
`- Status: ${report.status}`,
|
|
4130
4147
|
`- Source: ${report.source}`,
|
|
4131
|
-
`- Best provider: ${report.
|
|
4148
|
+
`- Best provider mix: ${formatProviderMix(report.bestProviders)}`,
|
|
4132
4149
|
`- Provider comparisons: ${String(report.summary.providerComparisonCount)}`,
|
|
4133
4150
|
`- Recommended actions: ${String(report.summary.recommendedActions)}`,
|
|
4134
4151
|
"",
|
|
@@ -4151,7 +4168,7 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
|
|
|
4151
4168
|
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("");
|
|
4152
4169
|
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml3(issue)}</li>`).join("");
|
|
4153
4170
|
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("");
|
|
4154
|
-
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 ${escapeHtml3(report.
|
|
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>`;
|
|
4155
4172
|
};
|
|
4156
4173
|
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
4157
4174
|
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|
package/dist/index.js
CHANGED
|
@@ -14641,6 +14641,18 @@ var shouldSwitchProvider = (current, best, options) => {
|
|
|
14641
14641
|
const improvementRatio = current.p95Ms > 0 ? improvementMs / current.p95Ms : 0;
|
|
14642
14642
|
return improvementMs >= minImprovementMs || improvementRatio >= minImprovementRatio;
|
|
14643
14643
|
};
|
|
14644
|
+
var bestProviderByRole = (providers) => {
|
|
14645
|
+
const best = new Map;
|
|
14646
|
+
for (const provider of providers) {
|
|
14647
|
+
const role = provider.role ?? provider.id;
|
|
14648
|
+
const existing = best.get(role);
|
|
14649
|
+
if (!existing || compareProviders(provider, existing) < 0) {
|
|
14650
|
+
best.set(role, provider);
|
|
14651
|
+
}
|
|
14652
|
+
}
|
|
14653
|
+
return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
|
|
14654
|
+
};
|
|
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(", ");
|
|
14644
14656
|
var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
|
|
14645
14657
|
const issues = [];
|
|
14646
14658
|
const requiredStatus = input.requireStatus ?? "pass";
|
|
@@ -14757,8 +14769,11 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
14757
14769
|
const runtimeChannel = readProofTrendRuntimeChannel(report);
|
|
14758
14770
|
const providers = summarizeProofTrendProviders(report, budgets.maxProviderP95Ms);
|
|
14759
14771
|
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
14772
|
+
const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
|
|
14760
14773
|
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
14761
|
-
const
|
|
14774
|
+
const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
|
|
14775
|
+
const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
|
|
14776
|
+
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
|
|
14762
14777
|
const recommendations = [];
|
|
14763
14778
|
const issues = [];
|
|
14764
14779
|
if (report.ok !== true) {
|
|
@@ -14766,19 +14781,20 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
14766
14781
|
}
|
|
14767
14782
|
recommendations.push({
|
|
14768
14783
|
evidence: {
|
|
14769
|
-
bestProviderId: bestProvider?.id,
|
|
14770
|
-
|
|
14784
|
+
bestProviderId: currentProvider || hasSingleProviderRole ? bestComparableProvider?.id ?? bestProvider?.id : undefined,
|
|
14785
|
+
bestProviderMix: formatProviderMix(bestProviders),
|
|
14786
|
+
bestProviderP95Ms: currentProvider || hasSingleProviderRole ? bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms : undefined,
|
|
14771
14787
|
budgetMs: budgets.maxProviderP95Ms,
|
|
14772
14788
|
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
14773
14789
|
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
14774
14790
|
providerComparisonCount: providers.length,
|
|
14775
14791
|
providerP95Ms: maxProviderP95Ms
|
|
14776
14792
|
},
|
|
14777
|
-
nextMove: providers.length > 0 ? providerSwitchRecommended ? `Route latency-sensitive
|
|
14778
|
-
providerId:
|
|
14779
|
-
recommendation: providers.length > 0 ? providerSwitchRecommended ? `Switch latency-sensitive routing to ${
|
|
14780
|
-
role:
|
|
14781
|
-
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
14793
|
+
nextMove: providers.length > 0 ? providerSwitchRecommended ? `Route latency-sensitive ${currentProvider?.role ?? "provider"} traffic to ${bestComparableProvider?.label ?? bestComparableProvider?.id} for this call profile and keep the current path as fallback.` : bestProviders.length > 0 ? `Use the fastest proven provider mix for this call profile: ${formatProviderMix(bestProviders)}.` : "Collect provider-specific sustained samples before making provider-specific routing decisions." : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep the current provider route for latency-sensitive turns and keep collecting sustained proof." : "Route latency-sensitive turns to a faster provider profile or tighten fallback/circuit-breaker budgets before promotion.",
|
|
14794
|
+
providerId: providerSwitchRecommended ? bestComparableProvider?.id : bestProviders.length === 1 ? bestProviders[0]?.id : undefined,
|
|
14795
|
+
recommendation: providers.length > 0 ? providerSwitchRecommended ? `Switch latency-sensitive ${currentProvider?.role ?? "provider"} routing to ${bestComparableProvider?.label ?? bestComparableProvider?.id}` : bestProviders.length > 0 ? "Prefer the fastest proven provider mix for this call profile" : "Collect provider-specific latency samples" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep current provider path" : "Change provider routing for latency-sensitive traffic",
|
|
14796
|
+
role: currentProvider || hasSingleProviderRole ? bestComparableProvider?.role : undefined,
|
|
14797
|
+
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProviders.length > 0 ? "pass" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
14782
14798
|
surface: "provider-path"
|
|
14783
14799
|
});
|
|
14784
14800
|
const runtimePass = withinBudget(runtimeChannel.maxFirstAudioLatencyMs, budgets.maxRuntimeFirstAudioLatencyMs) && withinBudget(runtimeChannel.maxInterruptionP95Ms, budgets.maxRuntimeInterruptionP95Ms) && withinBudget(runtimeChannel.maxJitterMs, budgets.maxRuntimeJitterMs) && withinBudget(runtimeChannel.maxTimestampDriftMs, budgets.maxRuntimeTimestampDriftMs) && withinBudget(runtimeChannel.maxBackpressureEvents, budgets.maxRuntimeBackpressureEvents);
|
|
@@ -14822,6 +14838,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
14822
14838
|
const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
|
|
14823
14839
|
return {
|
|
14824
14840
|
bestProvider,
|
|
14841
|
+
bestProviders,
|
|
14825
14842
|
generatedAt: new Date().toISOString(),
|
|
14826
14843
|
issues,
|
|
14827
14844
|
ok: status !== "fail",
|
|
@@ -14845,7 +14862,7 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
|
|
|
14845
14862
|
"",
|
|
14846
14863
|
`- Status: ${report.status}`,
|
|
14847
14864
|
`- Source: ${report.source}`,
|
|
14848
|
-
`- Best provider: ${report.
|
|
14865
|
+
`- Best provider mix: ${formatProviderMix(report.bestProviders)}`,
|
|
14849
14866
|
`- Provider comparisons: ${String(report.summary.providerComparisonCount)}`,
|
|
14850
14867
|
`- Recommended actions: ${String(report.summary.recommendedActions)}`,
|
|
14851
14868
|
"",
|
|
@@ -14868,7 +14885,7 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
|
|
|
14868
14885
|
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("");
|
|
14869
14886
|
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml22(issue)}</li>`).join("");
|
|
14870
14887
|
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("");
|
|
14871
|
-
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 ${escapeHtml22(report.
|
|
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>`;
|
|
14872
14889
|
};
|
|
14873
14890
|
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
14874
14891
|
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|
package/dist/proofTrends.d.ts
CHANGED
|
@@ -145,6 +145,7 @@ export type VoiceProofTrendProviderRecommendation = {
|
|
|
145
145
|
};
|
|
146
146
|
export type VoiceProofTrendRecommendationReport = {
|
|
147
147
|
bestProvider?: VoiceProofTrendProviderRecommendation;
|
|
148
|
+
bestProviders: VoiceProofTrendProviderRecommendation[];
|
|
148
149
|
generatedAt: string;
|
|
149
150
|
issues: string[];
|
|
150
151
|
ok: boolean;
|
package/dist/react/index.js
CHANGED
|
@@ -1672,6 +1672,18 @@ var shouldSwitchProvider = (current, best, options) => {
|
|
|
1672
1672
|
const improvementRatio = current.p95Ms > 0 ? improvementMs / current.p95Ms : 0;
|
|
1673
1673
|
return improvementMs >= minImprovementMs || improvementRatio >= minImprovementRatio;
|
|
1674
1674
|
};
|
|
1675
|
+
var bestProviderByRole = (providers) => {
|
|
1676
|
+
const best = new Map;
|
|
1677
|
+
for (const provider of providers) {
|
|
1678
|
+
const role = provider.role ?? provider.id;
|
|
1679
|
+
const existing = best.get(role);
|
|
1680
|
+
if (!existing || compareProviders(provider, existing) < 0) {
|
|
1681
|
+
best.set(role, provider);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
|
|
1685
|
+
};
|
|
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(", ");
|
|
1675
1687
|
var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
|
|
1676
1688
|
const issues = [];
|
|
1677
1689
|
const requiredStatus = input.requireStatus ?? "pass";
|
|
@@ -1788,8 +1800,11 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1788
1800
|
const runtimeChannel = readProofTrendRuntimeChannel(report);
|
|
1789
1801
|
const providers = summarizeProofTrendProviders(report, budgets.maxProviderP95Ms);
|
|
1790
1802
|
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
1803
|
+
const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
|
|
1791
1804
|
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
1792
|
-
const
|
|
1805
|
+
const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
|
|
1806
|
+
const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
|
|
1807
|
+
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
|
|
1793
1808
|
const recommendations = [];
|
|
1794
1809
|
const issues = [];
|
|
1795
1810
|
if (report.ok !== true) {
|
|
@@ -1797,19 +1812,20 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1797
1812
|
}
|
|
1798
1813
|
recommendations.push({
|
|
1799
1814
|
evidence: {
|
|
1800
|
-
bestProviderId: bestProvider?.id,
|
|
1801
|
-
|
|
1815
|
+
bestProviderId: currentProvider || hasSingleProviderRole ? bestComparableProvider?.id ?? bestProvider?.id : undefined,
|
|
1816
|
+
bestProviderMix: formatProviderMix(bestProviders),
|
|
1817
|
+
bestProviderP95Ms: currentProvider || hasSingleProviderRole ? bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms : undefined,
|
|
1802
1818
|
budgetMs: budgets.maxProviderP95Ms,
|
|
1803
1819
|
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
1804
1820
|
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
1805
1821
|
providerComparisonCount: providers.length,
|
|
1806
1822
|
providerP95Ms: maxProviderP95Ms
|
|
1807
1823
|
},
|
|
1808
|
-
nextMove: providers.length > 0 ? providerSwitchRecommended ? `Route latency-sensitive
|
|
1809
|
-
providerId:
|
|
1810
|
-
recommendation: providers.length > 0 ? providerSwitchRecommended ? `Switch latency-sensitive routing to ${
|
|
1811
|
-
role:
|
|
1812
|
-
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
1824
|
+
nextMove: providers.length > 0 ? providerSwitchRecommended ? `Route latency-sensitive ${currentProvider?.role ?? "provider"} traffic to ${bestComparableProvider?.label ?? bestComparableProvider?.id} for this call profile and keep the current path as fallback.` : bestProviders.length > 0 ? `Use the fastest proven provider mix for this call profile: ${formatProviderMix(bestProviders)}.` : "Collect provider-specific sustained samples before making provider-specific routing decisions." : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep the current provider route for latency-sensitive turns and keep collecting sustained proof." : "Route latency-sensitive turns to a faster provider profile or tighten fallback/circuit-breaker budgets before promotion.",
|
|
1825
|
+
providerId: providerSwitchRecommended ? bestComparableProvider?.id : bestProviders.length === 1 ? bestProviders[0]?.id : undefined,
|
|
1826
|
+
recommendation: providers.length > 0 ? providerSwitchRecommended ? `Switch latency-sensitive ${currentProvider?.role ?? "provider"} routing to ${bestComparableProvider?.label ?? bestComparableProvider?.id}` : bestProviders.length > 0 ? "Prefer the fastest proven provider mix for this call profile" : "Collect provider-specific latency samples" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep current provider path" : "Change provider routing for latency-sensitive traffic",
|
|
1827
|
+
role: currentProvider || hasSingleProviderRole ? bestComparableProvider?.role : undefined,
|
|
1828
|
+
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProviders.length > 0 ? "pass" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
1813
1829
|
surface: "provider-path"
|
|
1814
1830
|
});
|
|
1815
1831
|
const runtimePass = withinBudget(runtimeChannel.maxFirstAudioLatencyMs, budgets.maxRuntimeFirstAudioLatencyMs) && withinBudget(runtimeChannel.maxInterruptionP95Ms, budgets.maxRuntimeInterruptionP95Ms) && withinBudget(runtimeChannel.maxJitterMs, budgets.maxRuntimeJitterMs) && withinBudget(runtimeChannel.maxTimestampDriftMs, budgets.maxRuntimeTimestampDriftMs) && withinBudget(runtimeChannel.maxBackpressureEvents, budgets.maxRuntimeBackpressureEvents);
|
|
@@ -1853,6 +1869,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1853
1869
|
const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
|
|
1854
1870
|
return {
|
|
1855
1871
|
bestProvider,
|
|
1872
|
+
bestProviders,
|
|
1856
1873
|
generatedAt: new Date().toISOString(),
|
|
1857
1874
|
issues,
|
|
1858
1875
|
ok: status !== "fail",
|
|
@@ -1876,7 +1893,7 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
|
|
|
1876
1893
|
"",
|
|
1877
1894
|
`- Status: ${report.status}`,
|
|
1878
1895
|
`- Source: ${report.source}`,
|
|
1879
|
-
`- Best provider: ${report.
|
|
1896
|
+
`- Best provider mix: ${formatProviderMix(report.bestProviders)}`,
|
|
1880
1897
|
`- Provider comparisons: ${String(report.summary.providerComparisonCount)}`,
|
|
1881
1898
|
`- Recommended actions: ${String(report.summary.recommendedActions)}`,
|
|
1882
1899
|
"",
|
|
@@ -1899,7 +1916,7 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
|
|
|
1899
1916
|
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("");
|
|
1900
1917
|
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
|
|
1901
1918
|
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("");
|
|
1902
|
-
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 ${escapeHtml5(report.
|
|
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>`;
|
|
1903
1920
|
};
|
|
1904
1921
|
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
1905
1922
|
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|
package/dist/vue/index.js
CHANGED
|
@@ -1593,6 +1593,18 @@ var shouldSwitchProvider = (current, best, options) => {
|
|
|
1593
1593
|
const improvementRatio = current.p95Ms > 0 ? improvementMs / current.p95Ms : 0;
|
|
1594
1594
|
return improvementMs >= minImprovementMs || improvementRatio >= minImprovementRatio;
|
|
1595
1595
|
};
|
|
1596
|
+
var bestProviderByRole = (providers) => {
|
|
1597
|
+
const best = new Map;
|
|
1598
|
+
for (const provider of providers) {
|
|
1599
|
+
const role = provider.role ?? provider.id;
|
|
1600
|
+
const existing = best.get(role);
|
|
1601
|
+
if (!existing || compareProviders(provider, existing) < 0) {
|
|
1602
|
+
best.set(role, provider);
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
|
|
1606
|
+
};
|
|
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(", ");
|
|
1596
1608
|
var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
|
|
1597
1609
|
const issues = [];
|
|
1598
1610
|
const requiredStatus = input.requireStatus ?? "pass";
|
|
@@ -1709,8 +1721,11 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1709
1721
|
const runtimeChannel = readProofTrendRuntimeChannel(report);
|
|
1710
1722
|
const providers = summarizeProofTrendProviders(report, budgets.maxProviderP95Ms);
|
|
1711
1723
|
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
1724
|
+
const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
|
|
1712
1725
|
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
1713
|
-
const
|
|
1726
|
+
const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
|
|
1727
|
+
const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
|
|
1728
|
+
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
|
|
1714
1729
|
const recommendations = [];
|
|
1715
1730
|
const issues = [];
|
|
1716
1731
|
if (report.ok !== true) {
|
|
@@ -1718,19 +1733,20 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1718
1733
|
}
|
|
1719
1734
|
recommendations.push({
|
|
1720
1735
|
evidence: {
|
|
1721
|
-
bestProviderId: bestProvider?.id,
|
|
1722
|
-
|
|
1736
|
+
bestProviderId: currentProvider || hasSingleProviderRole ? bestComparableProvider?.id ?? bestProvider?.id : undefined,
|
|
1737
|
+
bestProviderMix: formatProviderMix(bestProviders),
|
|
1738
|
+
bestProviderP95Ms: currentProvider || hasSingleProviderRole ? bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms : undefined,
|
|
1723
1739
|
budgetMs: budgets.maxProviderP95Ms,
|
|
1724
1740
|
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
1725
1741
|
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
1726
1742
|
providerComparisonCount: providers.length,
|
|
1727
1743
|
providerP95Ms: maxProviderP95Ms
|
|
1728
1744
|
},
|
|
1729
|
-
nextMove: providers.length > 0 ? providerSwitchRecommended ? `Route latency-sensitive
|
|
1730
|
-
providerId:
|
|
1731
|
-
recommendation: providers.length > 0 ? providerSwitchRecommended ? `Switch latency-sensitive routing to ${
|
|
1732
|
-
role:
|
|
1733
|
-
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
1745
|
+
nextMove: providers.length > 0 ? providerSwitchRecommended ? `Route latency-sensitive ${currentProvider?.role ?? "provider"} traffic to ${bestComparableProvider?.label ?? bestComparableProvider?.id} for this call profile and keep the current path as fallback.` : bestProviders.length > 0 ? `Use the fastest proven provider mix for this call profile: ${formatProviderMix(bestProviders)}.` : "Collect provider-specific sustained samples before making provider-specific routing decisions." : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep the current provider route for latency-sensitive turns and keep collecting sustained proof." : "Route latency-sensitive turns to a faster provider profile or tighten fallback/circuit-breaker budgets before promotion.",
|
|
1746
|
+
providerId: providerSwitchRecommended ? bestComparableProvider?.id : bestProviders.length === 1 ? bestProviders[0]?.id : undefined,
|
|
1747
|
+
recommendation: providers.length > 0 ? providerSwitchRecommended ? `Switch latency-sensitive ${currentProvider?.role ?? "provider"} routing to ${bestComparableProvider?.label ?? bestComparableProvider?.id}` : bestProviders.length > 0 ? "Prefer the fastest proven provider mix for this call profile" : "Collect provider-specific latency samples" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep current provider path" : "Change provider routing for latency-sensitive traffic",
|
|
1748
|
+
role: currentProvider || hasSingleProviderRole ? bestComparableProvider?.role : undefined,
|
|
1749
|
+
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProviders.length > 0 ? "pass" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
1734
1750
|
surface: "provider-path"
|
|
1735
1751
|
});
|
|
1736
1752
|
const runtimePass = withinBudget(runtimeChannel.maxFirstAudioLatencyMs, budgets.maxRuntimeFirstAudioLatencyMs) && withinBudget(runtimeChannel.maxInterruptionP95Ms, budgets.maxRuntimeInterruptionP95Ms) && withinBudget(runtimeChannel.maxJitterMs, budgets.maxRuntimeJitterMs) && withinBudget(runtimeChannel.maxTimestampDriftMs, budgets.maxRuntimeTimestampDriftMs) && withinBudget(runtimeChannel.maxBackpressureEvents, budgets.maxRuntimeBackpressureEvents);
|
|
@@ -1774,6 +1790,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1774
1790
|
const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
|
|
1775
1791
|
return {
|
|
1776
1792
|
bestProvider,
|
|
1793
|
+
bestProviders,
|
|
1777
1794
|
generatedAt: new Date().toISOString(),
|
|
1778
1795
|
issues,
|
|
1779
1796
|
ok: status !== "fail",
|
|
@@ -1797,7 +1814,7 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
|
|
|
1797
1814
|
"",
|
|
1798
1815
|
`- Status: ${report.status}`,
|
|
1799
1816
|
`- Source: ${report.source}`,
|
|
1800
|
-
`- Best provider: ${report.
|
|
1817
|
+
`- Best provider mix: ${formatProviderMix(report.bestProviders)}`,
|
|
1801
1818
|
`- Provider comparisons: ${String(report.summary.providerComparisonCount)}`,
|
|
1802
1819
|
`- Recommended actions: ${String(report.summary.recommendedActions)}`,
|
|
1803
1820
|
"",
|
|
@@ -1820,7 +1837,7 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
|
|
|
1820
1837
|
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("");
|
|
1821
1838
|
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
|
|
1822
1839
|
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("");
|
|
1823
|
-
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 ${escapeHtml5(report.
|
|
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>`;
|
|
1824
1841
|
};
|
|
1825
1842
|
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
1826
1843
|
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|