@absolutejs/voice 0.0.22-beta.336 → 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.
- package/dist/client/index.js +53 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +53 -7
- package/dist/proofTrends.d.ts +22 -0
- package/dist/react/index.js +53 -7
- package/dist/vue/index.js +53 -7
- package/package.json +1 -1
package/dist/client/index.js
CHANGED
|
@@ -3935,7 +3935,35 @@ var bestProviderByRole = (providers) => {
|
|
|
3935
3935
|
}
|
|
3936
3936
|
return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
|
|
3937
3937
|
};
|
|
3938
|
-
var formatProviderMix = (providers) => providers.length === 0 ? "n/a" : providers.map((provider) => provider.role ? `${provider.role.toUpperCase()} ${provider.label ?? provider.id}` : provider.label ?? provider.id).join(", ");
|
|
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";
|
|
@@ -4054,8 +4082,10 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
4054
4082
|
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
4055
4083
|
const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
|
|
4056
4084
|
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
4085
|
+
const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
|
|
4057
4086
|
const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
|
|
4058
4087
|
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
|
|
4088
|
+
const profileRecommendations = buildProfileRecommendations(report, budgets);
|
|
4059
4089
|
const recommendations = [];
|
|
4060
4090
|
const issues = [];
|
|
4061
4091
|
if (report.ok !== true) {
|
|
@@ -4063,9 +4093,9 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
4063
4093
|
}
|
|
4064
4094
|
recommendations.push({
|
|
4065
4095
|
evidence: {
|
|
4066
|
-
bestProviderId: bestComparableProvider?.id ?? bestProvider?.id,
|
|
4096
|
+
bestProviderId: currentProvider || hasSingleProviderRole ? bestComparableProvider?.id ?? bestProvider?.id : undefined,
|
|
4067
4097
|
bestProviderMix: formatProviderMix(bestProviders),
|
|
4068
|
-
bestProviderP95Ms: bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms,
|
|
4098
|
+
bestProviderP95Ms: currentProvider || hasSingleProviderRole ? bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms : undefined,
|
|
4069
4099
|
budgetMs: budgets.maxProviderP95Ms,
|
|
4070
4100
|
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
4071
4101
|
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
@@ -4075,7 +4105,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
4075
4105
|
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.",
|
|
4076
4106
|
providerId: providerSwitchRecommended ? bestComparableProvider?.id : bestProviders.length === 1 ? bestProviders[0]?.id : undefined,
|
|
4077
4107
|
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",
|
|
4078
|
-
role: bestComparableProvider?.role,
|
|
4108
|
+
role: currentProvider || hasSingleProviderRole ? bestComparableProvider?.role : undefined,
|
|
4079
4109
|
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProviders.length > 0 ? "pass" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
4080
4110
|
surface: "provider-path"
|
|
4081
4111
|
});
|
|
@@ -4118,16 +4148,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
4118
4148
|
surface: "turn-latency"
|
|
4119
4149
|
});
|
|
4120
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;
|
|
4121
4159
|
return {
|
|
4122
4160
|
bestProvider,
|
|
4123
4161
|
bestProviders,
|
|
4124
4162
|
generatedAt: new Date().toISOString(),
|
|
4125
4163
|
issues,
|
|
4126
|
-
ok:
|
|
4164
|
+
ok: combinedStatus !== "fail",
|
|
4165
|
+
profiles: profileRecommendations,
|
|
4127
4166
|
providers,
|
|
4128
4167
|
recommendations,
|
|
4129
4168
|
source: report.source || report.outputDir || report.runId || "proof-trends",
|
|
4130
|
-
status,
|
|
4169
|
+
status: combinedStatus,
|
|
4131
4170
|
summary: {
|
|
4132
4171
|
keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
|
|
4133
4172
|
keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
|
|
@@ -4158,6 +4197,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
|
|
|
4158
4197
|
"| ---: | --- | --- | --- | ---: | ---: | --- |",
|
|
4159
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. |"],
|
|
4160
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
|
+
"",
|
|
4161
4206
|
"## Issues",
|
|
4162
4207
|
"",
|
|
4163
4208
|
...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
|
|
@@ -4167,7 +4212,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
|
|
|
4167
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("");
|
|
4168
4213
|
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml3(issue)}</li>`).join("");
|
|
4169
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("");
|
|
4170
|
-
|
|
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>`;
|
|
4171
4217
|
};
|
|
4172
4218
|
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
4173
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
|
@@ -14652,7 +14652,35 @@ var bestProviderByRole = (providers) => {
|
|
|
14652
14652
|
}
|
|
14653
14653
|
return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
|
|
14654
14654
|
};
|
|
14655
|
-
var formatProviderMix = (providers) => providers.length === 0 ? "n/a" : providers.map((provider) => provider.role ? `${provider.role.toUpperCase()} ${provider.label ?? provider.id}` : provider.label ?? provider.id).join(", ");
|
|
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";
|
|
@@ -14771,8 +14799,10 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
14771
14799
|
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
14772
14800
|
const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
|
|
14773
14801
|
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
14802
|
+
const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
|
|
14774
14803
|
const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
|
|
14775
14804
|
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
|
|
14805
|
+
const profileRecommendations = buildProfileRecommendations(report, budgets);
|
|
14776
14806
|
const recommendations = [];
|
|
14777
14807
|
const issues = [];
|
|
14778
14808
|
if (report.ok !== true) {
|
|
@@ -14780,9 +14810,9 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
14780
14810
|
}
|
|
14781
14811
|
recommendations.push({
|
|
14782
14812
|
evidence: {
|
|
14783
|
-
bestProviderId: bestComparableProvider?.id ?? bestProvider?.id,
|
|
14813
|
+
bestProviderId: currentProvider || hasSingleProviderRole ? bestComparableProvider?.id ?? bestProvider?.id : undefined,
|
|
14784
14814
|
bestProviderMix: formatProviderMix(bestProviders),
|
|
14785
|
-
bestProviderP95Ms: bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms,
|
|
14815
|
+
bestProviderP95Ms: currentProvider || hasSingleProviderRole ? bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms : undefined,
|
|
14786
14816
|
budgetMs: budgets.maxProviderP95Ms,
|
|
14787
14817
|
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
14788
14818
|
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
@@ -14792,7 +14822,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
14792
14822
|
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.",
|
|
14793
14823
|
providerId: providerSwitchRecommended ? bestComparableProvider?.id : bestProviders.length === 1 ? bestProviders[0]?.id : undefined,
|
|
14794
14824
|
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",
|
|
14795
|
-
role: bestComparableProvider?.role,
|
|
14825
|
+
role: currentProvider || hasSingleProviderRole ? bestComparableProvider?.role : undefined,
|
|
14796
14826
|
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProviders.length > 0 ? "pass" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
14797
14827
|
surface: "provider-path"
|
|
14798
14828
|
});
|
|
@@ -14835,16 +14865,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
14835
14865
|
surface: "turn-latency"
|
|
14836
14866
|
});
|
|
14837
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;
|
|
14838
14876
|
return {
|
|
14839
14877
|
bestProvider,
|
|
14840
14878
|
bestProviders,
|
|
14841
14879
|
generatedAt: new Date().toISOString(),
|
|
14842
14880
|
issues,
|
|
14843
|
-
ok:
|
|
14881
|
+
ok: combinedStatus !== "fail",
|
|
14882
|
+
profiles: profileRecommendations,
|
|
14844
14883
|
providers,
|
|
14845
14884
|
recommendations,
|
|
14846
14885
|
source: report.source || report.outputDir || report.runId || "proof-trends",
|
|
14847
|
-
status,
|
|
14886
|
+
status: combinedStatus,
|
|
14848
14887
|
summary: {
|
|
14849
14888
|
keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
|
|
14850
14889
|
keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
|
|
@@ -14875,6 +14914,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
|
|
|
14875
14914
|
"| ---: | --- | --- | --- | ---: | ---: | --- |",
|
|
14876
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. |"],
|
|
14877
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
|
+
"",
|
|
14878
14923
|
"## Issues",
|
|
14879
14924
|
"",
|
|
14880
14925
|
...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
|
|
@@ -14884,7 +14929,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
|
|
|
14884
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("");
|
|
14885
14930
|
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml22(issue)}</li>`).join("");
|
|
14886
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("");
|
|
14887
|
-
|
|
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>`;
|
|
14888
14934
|
};
|
|
14889
14935
|
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
14890
14936
|
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|
package/dist/proofTrends.d.ts
CHANGED
|
@@ -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;
|
package/dist/react/index.js
CHANGED
|
@@ -1683,7 +1683,35 @@ var bestProviderByRole = (providers) => {
|
|
|
1683
1683
|
}
|
|
1684
1684
|
return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
|
|
1685
1685
|
};
|
|
1686
|
-
var formatProviderMix = (providers) => providers.length === 0 ? "n/a" : providers.map((provider) => provider.role ? `${provider.role.toUpperCase()} ${provider.label ?? provider.id}` : provider.label ?? provider.id).join(", ");
|
|
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";
|
|
@@ -1802,8 +1830,10 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1802
1830
|
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
1803
1831
|
const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
|
|
1804
1832
|
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
1833
|
+
const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
|
|
1805
1834
|
const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
|
|
1806
1835
|
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
|
|
1836
|
+
const profileRecommendations = buildProfileRecommendations(report, budgets);
|
|
1807
1837
|
const recommendations = [];
|
|
1808
1838
|
const issues = [];
|
|
1809
1839
|
if (report.ok !== true) {
|
|
@@ -1811,9 +1841,9 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1811
1841
|
}
|
|
1812
1842
|
recommendations.push({
|
|
1813
1843
|
evidence: {
|
|
1814
|
-
bestProviderId: bestComparableProvider?.id ?? bestProvider?.id,
|
|
1844
|
+
bestProviderId: currentProvider || hasSingleProviderRole ? bestComparableProvider?.id ?? bestProvider?.id : undefined,
|
|
1815
1845
|
bestProviderMix: formatProviderMix(bestProviders),
|
|
1816
|
-
bestProviderP95Ms: bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms,
|
|
1846
|
+
bestProviderP95Ms: currentProvider || hasSingleProviderRole ? bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms : undefined,
|
|
1817
1847
|
budgetMs: budgets.maxProviderP95Ms,
|
|
1818
1848
|
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
1819
1849
|
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
@@ -1823,7 +1853,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1823
1853
|
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.",
|
|
1824
1854
|
providerId: providerSwitchRecommended ? bestComparableProvider?.id : bestProviders.length === 1 ? bestProviders[0]?.id : undefined,
|
|
1825
1855
|
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",
|
|
1826
|
-
role: bestComparableProvider?.role,
|
|
1856
|
+
role: currentProvider || hasSingleProviderRole ? bestComparableProvider?.role : undefined,
|
|
1827
1857
|
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProviders.length > 0 ? "pass" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
1828
1858
|
surface: "provider-path"
|
|
1829
1859
|
});
|
|
@@ -1866,16 +1896,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1866
1896
|
surface: "turn-latency"
|
|
1867
1897
|
});
|
|
1868
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;
|
|
1869
1907
|
return {
|
|
1870
1908
|
bestProvider,
|
|
1871
1909
|
bestProviders,
|
|
1872
1910
|
generatedAt: new Date().toISOString(),
|
|
1873
1911
|
issues,
|
|
1874
|
-
ok:
|
|
1912
|
+
ok: combinedStatus !== "fail",
|
|
1913
|
+
profiles: profileRecommendations,
|
|
1875
1914
|
providers,
|
|
1876
1915
|
recommendations,
|
|
1877
1916
|
source: report.source || report.outputDir || report.runId || "proof-trends",
|
|
1878
|
-
status,
|
|
1917
|
+
status: combinedStatus,
|
|
1879
1918
|
summary: {
|
|
1880
1919
|
keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
|
|
1881
1920
|
keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
|
|
@@ -1906,6 +1945,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
|
|
|
1906
1945
|
"| ---: | --- | --- | --- | ---: | ---: | --- |",
|
|
1907
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. |"],
|
|
1908
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
|
+
"",
|
|
1909
1954
|
"## Issues",
|
|
1910
1955
|
"",
|
|
1911
1956
|
...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
|
|
@@ -1915,7 +1960,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
|
|
|
1915
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("");
|
|
1916
1961
|
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
|
|
1917
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("");
|
|
1918
|
-
|
|
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>`;
|
|
1919
1965
|
};
|
|
1920
1966
|
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
1921
1967
|
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|
package/dist/vue/index.js
CHANGED
|
@@ -1604,7 +1604,35 @@ var bestProviderByRole = (providers) => {
|
|
|
1604
1604
|
}
|
|
1605
1605
|
return [...best.values()].sort((left, right) => String(left.role ?? left.id).localeCompare(String(right.role ?? right.id)));
|
|
1606
1606
|
};
|
|
1607
|
-
var formatProviderMix = (providers) => providers.length === 0 ? "n/a" : providers.map((provider) => provider.role ? `${provider.role.toUpperCase()} ${provider.label ?? provider.id}` : provider.label ?? provider.id).join(", ");
|
|
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";
|
|
@@ -1723,8 +1751,10 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1723
1751
|
const bestProvider = providers.find((provider) => provider.status === "pass") ?? providers[0];
|
|
1724
1752
|
const bestProviders = bestProviderByRole(providers).filter((provider) => provider.status === "pass");
|
|
1725
1753
|
const currentProvider = options.currentProviderId ? providers.find((provider) => provider.id === options.currentProviderId) : undefined;
|
|
1754
|
+
const hasSingleProviderRole = new Set(bestProviders.map((provider) => provider.role ?? provider.id)).size <= 1;
|
|
1726
1755
|
const bestComparableProvider = currentProvider?.role ? bestProviders.find((provider) => provider.role === currentProvider.role) : bestProvider;
|
|
1727
1756
|
const providerSwitchRecommended = shouldSwitchProvider(currentProvider, bestComparableProvider, options);
|
|
1757
|
+
const profileRecommendations = buildProfileRecommendations(report, budgets);
|
|
1728
1758
|
const recommendations = [];
|
|
1729
1759
|
const issues = [];
|
|
1730
1760
|
if (report.ok !== true) {
|
|
@@ -1732,9 +1762,9 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1732
1762
|
}
|
|
1733
1763
|
recommendations.push({
|
|
1734
1764
|
evidence: {
|
|
1735
|
-
bestProviderId: bestComparableProvider?.id ?? bestProvider?.id,
|
|
1765
|
+
bestProviderId: currentProvider || hasSingleProviderRole ? bestComparableProvider?.id ?? bestProvider?.id : undefined,
|
|
1736
1766
|
bestProviderMix: formatProviderMix(bestProviders),
|
|
1737
|
-
bestProviderP95Ms: bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms,
|
|
1767
|
+
bestProviderP95Ms: currentProvider || hasSingleProviderRole ? bestComparableProvider?.p95Ms ?? bestProvider?.p95Ms : undefined,
|
|
1738
1768
|
budgetMs: budgets.maxProviderP95Ms,
|
|
1739
1769
|
currentProviderId: currentProvider?.id ?? options.currentProviderId,
|
|
1740
1770
|
currentProviderP95Ms: currentProvider?.p95Ms,
|
|
@@ -1744,7 +1774,7 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1744
1774
|
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.",
|
|
1745
1775
|
providerId: providerSwitchRecommended ? bestComparableProvider?.id : bestProviders.length === 1 ? bestProviders[0]?.id : undefined,
|
|
1746
1776
|
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",
|
|
1747
|
-
role: bestComparableProvider?.role,
|
|
1777
|
+
role: currentProvider || hasSingleProviderRole ? bestComparableProvider?.role : undefined,
|
|
1748
1778
|
status: providers.length > 0 ? providerSwitchRecommended ? "warn" : bestProviders.length > 0 ? "pass" : bestProvider?.status ?? "fail" : withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
|
|
1749
1779
|
surface: "provider-path"
|
|
1750
1780
|
});
|
|
@@ -1787,16 +1817,25 @@ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
|
|
|
1787
1817
|
surface: "turn-latency"
|
|
1788
1818
|
});
|
|
1789
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;
|
|
1790
1828
|
return {
|
|
1791
1829
|
bestProvider,
|
|
1792
1830
|
bestProviders,
|
|
1793
1831
|
generatedAt: new Date().toISOString(),
|
|
1794
1832
|
issues,
|
|
1795
|
-
ok:
|
|
1833
|
+
ok: combinedStatus !== "fail",
|
|
1834
|
+
profiles: profileRecommendations,
|
|
1796
1835
|
providers,
|
|
1797
1836
|
recommendations,
|
|
1798
1837
|
source: report.source || report.outputDir || report.runId || "proof-trends",
|
|
1799
|
-
status,
|
|
1838
|
+
status: combinedStatus,
|
|
1800
1839
|
summary: {
|
|
1801
1840
|
keepCurrentProviderPath: !providerSwitchRecommended && recommendations.find((item) => item.surface === "provider-path")?.status !== "fail",
|
|
1802
1841
|
keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
|
|
@@ -1827,6 +1866,12 @@ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provid
|
|
|
1827
1866
|
"| ---: | --- | --- | --- | ---: | ---: | --- |",
|
|
1828
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. |"],
|
|
1829
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
|
+
"",
|
|
1830
1875
|
"## Issues",
|
|
1831
1876
|
"",
|
|
1832
1877
|
...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
|
|
@@ -1836,7 +1881,8 @@ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider R
|
|
|
1836
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("");
|
|
1837
1882
|
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
|
|
1838
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("");
|
|
1839
|
-
|
|
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>`;
|
|
1840
1886
|
};
|
|
1841
1887
|
var createVoiceProofTrendRecommendationRoutes = (options) => {
|
|
1842
1888
|
const path = options.path ?? "/api/voice/proof-trend-recommendations";
|