@absolutejs/voice 0.0.22-beta.386 → 0.0.22-beta.388
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 +69 -51
- package/dist/index.js +71 -53
- package/dist/proofTrends.d.ts +2 -0
- package/dist/react/index.js +69 -51
- package/dist/vue/index.js +69 -51
- package/package.json +1 -1
package/dist/client/index.js
CHANGED
|
@@ -5993,6 +5993,9 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
|
|
|
5993
5993
|
const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
|
|
5994
5994
|
const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
|
|
5995
5995
|
const surfaces = readRealCallProfileTraceSurfaces(sessionEvents);
|
|
5996
|
+
if (providers.length === 0 && runtimeChannel === undefined && liveLatencies.length === 0 && surfaces.length === 0) {
|
|
5997
|
+
return;
|
|
5998
|
+
}
|
|
5996
5999
|
return {
|
|
5997
6000
|
generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
|
|
5998
6001
|
liveP95Ms: percentile(liveLatencies, 95),
|
|
@@ -6554,6 +6557,7 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
6554
6557
|
const requestTimeoutMs = options.requestTimeoutMs ?? 5000;
|
|
6555
6558
|
const jobPollMs = options.jobPollMs ?? 1200;
|
|
6556
6559
|
const jobTimeoutMs = options.jobTimeoutMs ?? 600000;
|
|
6560
|
+
const maxPasses = typeof options.maxPasses === "number" && Number.isFinite(options.maxPasses) && options.maxPasses > 0 ? Math.floor(options.maxPasses) : 3;
|
|
6557
6561
|
const readinessCheckLabel = options.readinessCheckLabel ?? "Real-call profile history";
|
|
6558
6562
|
const fetchImpl = options.fetch ?? fetch;
|
|
6559
6563
|
const recoveryActionsHref = options.recoveryActionsHref ?? "/api/production-readiness/recovery-actions";
|
|
@@ -6595,70 +6599,84 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
6595
6599
|
actionCount: 0,
|
|
6596
6600
|
actions,
|
|
6597
6601
|
jobs: [],
|
|
6602
|
+
passes: 0,
|
|
6598
6603
|
ok: realCallProfileGate2?.status === "pass",
|
|
6599
6604
|
realCallProfileGate: realCallProfileGate2,
|
|
6600
6605
|
startFailures: []
|
|
6601
6606
|
};
|
|
6602
6607
|
}
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
return [];
|
|
6617
|
-
}
|
|
6618
|
-
return result.value.jobId ? [result.value] : [];
|
|
6619
|
-
});
|
|
6620
|
-
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
6621
|
-
{
|
|
6622
|
-
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
6623
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
6624
|
-
}
|
|
6625
|
-
] : []);
|
|
6626
|
-
const pollJob = async (jobId) => {
|
|
6627
|
-
const deadline = Date.now() + jobTimeoutMs;
|
|
6628
|
-
while (Date.now() < deadline) {
|
|
6629
|
-
const body = await fetchJson(resolveJobHref(jobId));
|
|
6630
|
-
const job = body.job;
|
|
6631
|
-
if (!job) {
|
|
6632
|
-
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
6608
|
+
const allJobs = [];
|
|
6609
|
+
const allStartFailures = [];
|
|
6610
|
+
let realCallProfileGate = null;
|
|
6611
|
+
let passes = 0;
|
|
6612
|
+
for (let pass = 1;pass <= maxPasses; pass += 1) {
|
|
6613
|
+
passes = pass;
|
|
6614
|
+
options.logger?.log(`Running ${String(actions.length)} real-call profile recovery action(s) in parallel (pass ${String(pass)}/${String(maxPasses)}).`);
|
|
6615
|
+
for (const action of actions) {
|
|
6616
|
+
options.logger?.log(`- ${describeVoiceRealCallProfileRecoveryLoopAction(action)}`);
|
|
6617
|
+
}
|
|
6618
|
+
const starts = await Promise.allSettled(actions.map(async (action) => {
|
|
6619
|
+
if (!action.href) {
|
|
6620
|
+
throw new Error("Recovery action is missing href.");
|
|
6633
6621
|
}
|
|
6634
|
-
|
|
6635
|
-
|
|
6622
|
+
const body = await fetchJson(action.href, { method: "POST" });
|
|
6623
|
+
return { action, ...body };
|
|
6624
|
+
}));
|
|
6625
|
+
const startedJobs = starts.flatMap((result) => {
|
|
6626
|
+
if (result.status === "rejected") {
|
|
6627
|
+
return [];
|
|
6636
6628
|
}
|
|
6637
|
-
|
|
6629
|
+
return result.value.jobId ? [result.value] : [];
|
|
6630
|
+
});
|
|
6631
|
+
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
6632
|
+
{
|
|
6633
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
6634
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
6635
|
+
}
|
|
6636
|
+
] : []);
|
|
6637
|
+
allStartFailures.push(...startFailures);
|
|
6638
|
+
const pollJob = async (jobId) => {
|
|
6639
|
+
const deadline = Date.now() + jobTimeoutMs;
|
|
6640
|
+
while (Date.now() < deadline) {
|
|
6641
|
+
const body = await fetchJson(resolveJobHref(jobId));
|
|
6642
|
+
const job = body.job;
|
|
6643
|
+
if (!job) {
|
|
6644
|
+
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
6645
|
+
}
|
|
6646
|
+
if (job.status === "pass" || job.status === "fail") {
|
|
6647
|
+
return job;
|
|
6648
|
+
}
|
|
6649
|
+
await sleepVoiceRealCallProfileRecoveryLoop(jobPollMs);
|
|
6650
|
+
}
|
|
6651
|
+
throw new Error(`Timed out waiting ${String(jobTimeoutMs)}ms for recovery job ${jobId}.`);
|
|
6652
|
+
};
|
|
6653
|
+
options.logger?.log(`Polling ${String(startedJobs.length)} recovery job(s) in parallel.`);
|
|
6654
|
+
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
6655
|
+
const jobs = jobResults.map((result, index) => ({
|
|
6656
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
6657
|
+
jobId: startedJobs[index]?.jobId,
|
|
6658
|
+
result: result.status === "fulfilled" ? result.value : {
|
|
6659
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
6660
|
+
status: "fail"
|
|
6661
|
+
}
|
|
6662
|
+
}));
|
|
6663
|
+
allJobs.push(...jobs);
|
|
6664
|
+
if (refreshHref !== false) {
|
|
6665
|
+
await fetchJson(refreshHref, { method: "POST" });
|
|
6638
6666
|
}
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
6643
|
-
const jobs = jobResults.map((result, index) => ({
|
|
6644
|
-
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
6645
|
-
jobId: startedJobs[index]?.jobId,
|
|
6646
|
-
result: result.status === "fulfilled" ? result.value : {
|
|
6647
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
6648
|
-
status: "fail"
|
|
6667
|
+
realCallProfileGate = await getGate(true);
|
|
6668
|
+
if (realCallProfileGate?.status === "pass") {
|
|
6669
|
+
break;
|
|
6649
6670
|
}
|
|
6650
|
-
}));
|
|
6651
|
-
if (refreshHref !== false) {
|
|
6652
|
-
await fetchJson(refreshHref, { method: "POST" });
|
|
6653
6671
|
}
|
|
6654
|
-
const realCallProfileGate = await getGate(true);
|
|
6655
6672
|
return {
|
|
6656
|
-
actionCount: actions.length,
|
|
6673
|
+
actionCount: actions.length * passes,
|
|
6657
6674
|
actions,
|
|
6658
|
-
jobs,
|
|
6659
|
-
|
|
6675
|
+
jobs: allJobs,
|
|
6676
|
+
passes,
|
|
6677
|
+
ok: allStartFailures.length === 0 && allJobs.every((job) => job.result.status === "pass") && realCallProfileGate?.status === "pass",
|
|
6660
6678
|
realCallProfileGate,
|
|
6661
|
-
startFailures
|
|
6679
|
+
startFailures: allStartFailures
|
|
6662
6680
|
};
|
|
6663
6681
|
};
|
|
6664
6682
|
var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|
package/dist/index.js
CHANGED
|
@@ -16512,6 +16512,9 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
|
|
|
16512
16512
|
const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
|
|
16513
16513
|
const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
|
|
16514
16514
|
const surfaces = readRealCallProfileTraceSurfaces(sessionEvents);
|
|
16515
|
+
if (providers.length === 0 && runtimeChannel === undefined && liveLatencies.length === 0 && surfaces.length === 0) {
|
|
16516
|
+
return;
|
|
16517
|
+
}
|
|
16515
16518
|
return {
|
|
16516
16519
|
generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
|
|
16517
16520
|
liveP95Ms: percentile2(liveLatencies, 95),
|
|
@@ -17073,6 +17076,7 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
17073
17076
|
const requestTimeoutMs = options.requestTimeoutMs ?? 5000;
|
|
17074
17077
|
const jobPollMs = options.jobPollMs ?? 1200;
|
|
17075
17078
|
const jobTimeoutMs = options.jobTimeoutMs ?? 600000;
|
|
17079
|
+
const maxPasses = typeof options.maxPasses === "number" && Number.isFinite(options.maxPasses) && options.maxPasses > 0 ? Math.floor(options.maxPasses) : 3;
|
|
17076
17080
|
const readinessCheckLabel = options.readinessCheckLabel ?? "Real-call profile history";
|
|
17077
17081
|
const fetchImpl = options.fetch ?? fetch;
|
|
17078
17082
|
const recoveryActionsHref = options.recoveryActionsHref ?? "/api/production-readiness/recovery-actions";
|
|
@@ -17114,70 +17118,84 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
17114
17118
|
actionCount: 0,
|
|
17115
17119
|
actions,
|
|
17116
17120
|
jobs: [],
|
|
17121
|
+
passes: 0,
|
|
17117
17122
|
ok: realCallProfileGate2?.status === "pass",
|
|
17118
17123
|
realCallProfileGate: realCallProfileGate2,
|
|
17119
17124
|
startFailures: []
|
|
17120
17125
|
};
|
|
17121
17126
|
}
|
|
17122
|
-
|
|
17123
|
-
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
|
|
17133
|
-
|
|
17134
|
-
|
|
17135
|
-
|
|
17127
|
+
const allJobs = [];
|
|
17128
|
+
const allStartFailures = [];
|
|
17129
|
+
let realCallProfileGate = null;
|
|
17130
|
+
let passes = 0;
|
|
17131
|
+
for (let pass = 1;pass <= maxPasses; pass += 1) {
|
|
17132
|
+
passes = pass;
|
|
17133
|
+
options.logger?.log(`Running ${String(actions.length)} real-call profile recovery action(s) in parallel (pass ${String(pass)}/${String(maxPasses)}).`);
|
|
17134
|
+
for (const action of actions) {
|
|
17135
|
+
options.logger?.log(`- ${describeVoiceRealCallProfileRecoveryLoopAction(action)}`);
|
|
17136
|
+
}
|
|
17137
|
+
const starts = await Promise.allSettled(actions.map(async (action) => {
|
|
17138
|
+
if (!action.href) {
|
|
17139
|
+
throw new Error("Recovery action is missing href.");
|
|
17140
|
+
}
|
|
17141
|
+
const body = await fetchJson(action.href, { method: "POST" });
|
|
17142
|
+
return { action, ...body };
|
|
17143
|
+
}));
|
|
17144
|
+
const startedJobs = starts.flatMap((result) => {
|
|
17145
|
+
if (result.status === "rejected") {
|
|
17146
|
+
return [];
|
|
17147
|
+
}
|
|
17148
|
+
return result.value.jobId ? [result.value] : [];
|
|
17149
|
+
});
|
|
17150
|
+
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
17151
|
+
{
|
|
17152
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
17153
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
17154
|
+
}
|
|
17155
|
+
] : []);
|
|
17156
|
+
allStartFailures.push(...startFailures);
|
|
17157
|
+
const pollJob = async (jobId) => {
|
|
17158
|
+
const deadline = Date.now() + jobTimeoutMs;
|
|
17159
|
+
while (Date.now() < deadline) {
|
|
17160
|
+
const body = await fetchJson(resolveJobHref(jobId));
|
|
17161
|
+
const job = body.job;
|
|
17162
|
+
if (!job) {
|
|
17163
|
+
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
17164
|
+
}
|
|
17165
|
+
if (job.status === "pass" || job.status === "fail") {
|
|
17166
|
+
return job;
|
|
17167
|
+
}
|
|
17168
|
+
await sleepVoiceRealCallProfileRecoveryLoop(jobPollMs);
|
|
17169
|
+
}
|
|
17170
|
+
throw new Error(`Timed out waiting ${String(jobTimeoutMs)}ms for recovery job ${jobId}.`);
|
|
17171
|
+
};
|
|
17172
|
+
options.logger?.log(`Polling ${String(startedJobs.length)} recovery job(s) in parallel.`);
|
|
17173
|
+
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
17174
|
+
const jobs = jobResults.map((result, index) => ({
|
|
17175
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
17176
|
+
jobId: startedJobs[index]?.jobId,
|
|
17177
|
+
result: result.status === "fulfilled" ? result.value : {
|
|
17178
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
17179
|
+
status: "fail"
|
|
17180
|
+
}
|
|
17181
|
+
}));
|
|
17182
|
+
allJobs.push(...jobs);
|
|
17183
|
+
if (refreshHref !== false) {
|
|
17184
|
+
await fetchJson(refreshHref, { method: "POST" });
|
|
17136
17185
|
}
|
|
17137
|
-
|
|
17138
|
-
|
|
17139
|
-
|
|
17140
|
-
{
|
|
17141
|
-
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
17142
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
17143
|
-
}
|
|
17144
|
-
] : []);
|
|
17145
|
-
const pollJob = async (jobId) => {
|
|
17146
|
-
const deadline = Date.now() + jobTimeoutMs;
|
|
17147
|
-
while (Date.now() < deadline) {
|
|
17148
|
-
const body = await fetchJson(resolveJobHref(jobId));
|
|
17149
|
-
const job = body.job;
|
|
17150
|
-
if (!job) {
|
|
17151
|
-
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
17152
|
-
}
|
|
17153
|
-
if (job.status === "pass" || job.status === "fail") {
|
|
17154
|
-
return job;
|
|
17155
|
-
}
|
|
17156
|
-
await sleepVoiceRealCallProfileRecoveryLoop(jobPollMs);
|
|
17157
|
-
}
|
|
17158
|
-
throw new Error(`Timed out waiting ${String(jobTimeoutMs)}ms for recovery job ${jobId}.`);
|
|
17159
|
-
};
|
|
17160
|
-
options.logger?.log(`Polling ${String(startedJobs.length)} recovery job(s) in parallel.`);
|
|
17161
|
-
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
17162
|
-
const jobs = jobResults.map((result, index) => ({
|
|
17163
|
-
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
17164
|
-
jobId: startedJobs[index]?.jobId,
|
|
17165
|
-
result: result.status === "fulfilled" ? result.value : {
|
|
17166
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
17167
|
-
status: "fail"
|
|
17186
|
+
realCallProfileGate = await getGate(true);
|
|
17187
|
+
if (realCallProfileGate?.status === "pass") {
|
|
17188
|
+
break;
|
|
17168
17189
|
}
|
|
17169
|
-
}));
|
|
17170
|
-
if (refreshHref !== false) {
|
|
17171
|
-
await fetchJson(refreshHref, { method: "POST" });
|
|
17172
17190
|
}
|
|
17173
|
-
const realCallProfileGate = await getGate(true);
|
|
17174
17191
|
return {
|
|
17175
|
-
actionCount: actions.length,
|
|
17192
|
+
actionCount: actions.length * passes,
|
|
17176
17193
|
actions,
|
|
17177
|
-
jobs,
|
|
17178
|
-
|
|
17194
|
+
jobs: allJobs,
|
|
17195
|
+
passes,
|
|
17196
|
+
ok: allStartFailures.length === 0 && allJobs.every((job) => job.result.status === "pass") && realCallProfileGate?.status === "pass",
|
|
17179
17197
|
realCallProfileGate,
|
|
17180
|
-
startFailures
|
|
17198
|
+
startFailures: allStartFailures
|
|
17181
17199
|
};
|
|
17182
17200
|
};
|
|
17183
17201
|
var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|
package/dist/proofTrends.d.ts
CHANGED
|
@@ -492,6 +492,7 @@ export type VoiceRealCallProfileRecoveryLoopReport = {
|
|
|
492
492
|
actionCount: number;
|
|
493
493
|
actions: VoiceRealCallProfileRecoveryLoopAction[];
|
|
494
494
|
jobs: VoiceRealCallProfileRecoveryLoopJobResult[];
|
|
495
|
+
passes: number;
|
|
495
496
|
ok: boolean;
|
|
496
497
|
realCallProfileGate: VoiceProductionReadinessCheck | null;
|
|
497
498
|
startFailures: VoiceRealCallProfileRecoveryLoopStartFailure[];
|
|
@@ -504,6 +505,7 @@ export type VoiceRealCallProfileRecoveryLoopOptions = {
|
|
|
504
505
|
jobPollMs?: number;
|
|
505
506
|
jobTimeoutMs?: number;
|
|
506
507
|
logger?: Pick<Console, 'log'>;
|
|
508
|
+
maxPasses?: number;
|
|
507
509
|
readinessCheckLabel?: string;
|
|
508
510
|
readinessHref?: string;
|
|
509
511
|
recoveryActionsHref?: string;
|
package/dist/react/index.js
CHANGED
|
@@ -3580,6 +3580,9 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
|
|
|
3580
3580
|
const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
|
|
3581
3581
|
const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
|
|
3582
3582
|
const surfaces = readRealCallProfileTraceSurfaces(sessionEvents);
|
|
3583
|
+
if (providers.length === 0 && runtimeChannel === undefined && liveLatencies.length === 0 && surfaces.length === 0) {
|
|
3584
|
+
return;
|
|
3585
|
+
}
|
|
3583
3586
|
return {
|
|
3584
3587
|
generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
|
|
3585
3588
|
liveP95Ms: percentile(liveLatencies, 95),
|
|
@@ -4141,6 +4144,7 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
4141
4144
|
const requestTimeoutMs = options.requestTimeoutMs ?? 5000;
|
|
4142
4145
|
const jobPollMs = options.jobPollMs ?? 1200;
|
|
4143
4146
|
const jobTimeoutMs = options.jobTimeoutMs ?? 600000;
|
|
4147
|
+
const maxPasses = typeof options.maxPasses === "number" && Number.isFinite(options.maxPasses) && options.maxPasses > 0 ? Math.floor(options.maxPasses) : 3;
|
|
4144
4148
|
const readinessCheckLabel = options.readinessCheckLabel ?? "Real-call profile history";
|
|
4145
4149
|
const fetchImpl = options.fetch ?? fetch;
|
|
4146
4150
|
const recoveryActionsHref = options.recoveryActionsHref ?? "/api/production-readiness/recovery-actions";
|
|
@@ -4182,70 +4186,84 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
4182
4186
|
actionCount: 0,
|
|
4183
4187
|
actions,
|
|
4184
4188
|
jobs: [],
|
|
4189
|
+
passes: 0,
|
|
4185
4190
|
ok: realCallProfileGate2?.status === "pass",
|
|
4186
4191
|
realCallProfileGate: realCallProfileGate2,
|
|
4187
4192
|
startFailures: []
|
|
4188
4193
|
};
|
|
4189
4194
|
}
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
return [];
|
|
4204
|
-
}
|
|
4205
|
-
return result.value.jobId ? [result.value] : [];
|
|
4206
|
-
});
|
|
4207
|
-
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
4208
|
-
{
|
|
4209
|
-
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
4210
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
4211
|
-
}
|
|
4212
|
-
] : []);
|
|
4213
|
-
const pollJob = async (jobId) => {
|
|
4214
|
-
const deadline = Date.now() + jobTimeoutMs;
|
|
4215
|
-
while (Date.now() < deadline) {
|
|
4216
|
-
const body = await fetchJson(resolveJobHref(jobId));
|
|
4217
|
-
const job = body.job;
|
|
4218
|
-
if (!job) {
|
|
4219
|
-
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
4195
|
+
const allJobs = [];
|
|
4196
|
+
const allStartFailures = [];
|
|
4197
|
+
let realCallProfileGate = null;
|
|
4198
|
+
let passes = 0;
|
|
4199
|
+
for (let pass = 1;pass <= maxPasses; pass += 1) {
|
|
4200
|
+
passes = pass;
|
|
4201
|
+
options.logger?.log(`Running ${String(actions.length)} real-call profile recovery action(s) in parallel (pass ${String(pass)}/${String(maxPasses)}).`);
|
|
4202
|
+
for (const action of actions) {
|
|
4203
|
+
options.logger?.log(`- ${describeVoiceRealCallProfileRecoveryLoopAction(action)}`);
|
|
4204
|
+
}
|
|
4205
|
+
const starts = await Promise.allSettled(actions.map(async (action) => {
|
|
4206
|
+
if (!action.href) {
|
|
4207
|
+
throw new Error("Recovery action is missing href.");
|
|
4220
4208
|
}
|
|
4221
|
-
|
|
4222
|
-
|
|
4209
|
+
const body = await fetchJson(action.href, { method: "POST" });
|
|
4210
|
+
return { action, ...body };
|
|
4211
|
+
}));
|
|
4212
|
+
const startedJobs = starts.flatMap((result) => {
|
|
4213
|
+
if (result.status === "rejected") {
|
|
4214
|
+
return [];
|
|
4223
4215
|
}
|
|
4224
|
-
|
|
4216
|
+
return result.value.jobId ? [result.value] : [];
|
|
4217
|
+
});
|
|
4218
|
+
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
4219
|
+
{
|
|
4220
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
4221
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
4222
|
+
}
|
|
4223
|
+
] : []);
|
|
4224
|
+
allStartFailures.push(...startFailures);
|
|
4225
|
+
const pollJob = async (jobId) => {
|
|
4226
|
+
const deadline = Date.now() + jobTimeoutMs;
|
|
4227
|
+
while (Date.now() < deadline) {
|
|
4228
|
+
const body = await fetchJson(resolveJobHref(jobId));
|
|
4229
|
+
const job = body.job;
|
|
4230
|
+
if (!job) {
|
|
4231
|
+
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
4232
|
+
}
|
|
4233
|
+
if (job.status === "pass" || job.status === "fail") {
|
|
4234
|
+
return job;
|
|
4235
|
+
}
|
|
4236
|
+
await sleepVoiceRealCallProfileRecoveryLoop(jobPollMs);
|
|
4237
|
+
}
|
|
4238
|
+
throw new Error(`Timed out waiting ${String(jobTimeoutMs)}ms for recovery job ${jobId}.`);
|
|
4239
|
+
};
|
|
4240
|
+
options.logger?.log(`Polling ${String(startedJobs.length)} recovery job(s) in parallel.`);
|
|
4241
|
+
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
4242
|
+
const jobs = jobResults.map((result, index) => ({
|
|
4243
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
4244
|
+
jobId: startedJobs[index]?.jobId,
|
|
4245
|
+
result: result.status === "fulfilled" ? result.value : {
|
|
4246
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
4247
|
+
status: "fail"
|
|
4248
|
+
}
|
|
4249
|
+
}));
|
|
4250
|
+
allJobs.push(...jobs);
|
|
4251
|
+
if (refreshHref !== false) {
|
|
4252
|
+
await fetchJson(refreshHref, { method: "POST" });
|
|
4225
4253
|
}
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
4230
|
-
const jobs = jobResults.map((result, index) => ({
|
|
4231
|
-
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
4232
|
-
jobId: startedJobs[index]?.jobId,
|
|
4233
|
-
result: result.status === "fulfilled" ? result.value : {
|
|
4234
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
4235
|
-
status: "fail"
|
|
4254
|
+
realCallProfileGate = await getGate(true);
|
|
4255
|
+
if (realCallProfileGate?.status === "pass") {
|
|
4256
|
+
break;
|
|
4236
4257
|
}
|
|
4237
|
-
}));
|
|
4238
|
-
if (refreshHref !== false) {
|
|
4239
|
-
await fetchJson(refreshHref, { method: "POST" });
|
|
4240
4258
|
}
|
|
4241
|
-
const realCallProfileGate = await getGate(true);
|
|
4242
4259
|
return {
|
|
4243
|
-
actionCount: actions.length,
|
|
4260
|
+
actionCount: actions.length * passes,
|
|
4244
4261
|
actions,
|
|
4245
|
-
jobs,
|
|
4246
|
-
|
|
4262
|
+
jobs: allJobs,
|
|
4263
|
+
passes,
|
|
4264
|
+
ok: allStartFailures.length === 0 && allJobs.every((job) => job.result.status === "pass") && realCallProfileGate?.status === "pass",
|
|
4247
4265
|
realCallProfileGate,
|
|
4248
|
-
startFailures
|
|
4266
|
+
startFailures: allStartFailures
|
|
4249
4267
|
};
|
|
4250
4268
|
};
|
|
4251
4269
|
var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|
package/dist/vue/index.js
CHANGED
|
@@ -3501,6 +3501,9 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
|
|
|
3501
3501
|
const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
|
|
3502
3502
|
const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
|
|
3503
3503
|
const surfaces = readRealCallProfileTraceSurfaces(sessionEvents);
|
|
3504
|
+
if (providers.length === 0 && runtimeChannel === undefined && liveLatencies.length === 0 && surfaces.length === 0) {
|
|
3505
|
+
return;
|
|
3506
|
+
}
|
|
3504
3507
|
return {
|
|
3505
3508
|
generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
|
|
3506
3509
|
liveP95Ms: percentile(liveLatencies, 95),
|
|
@@ -4062,6 +4065,7 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
4062
4065
|
const requestTimeoutMs = options.requestTimeoutMs ?? 5000;
|
|
4063
4066
|
const jobPollMs = options.jobPollMs ?? 1200;
|
|
4064
4067
|
const jobTimeoutMs = options.jobTimeoutMs ?? 600000;
|
|
4068
|
+
const maxPasses = typeof options.maxPasses === "number" && Number.isFinite(options.maxPasses) && options.maxPasses > 0 ? Math.floor(options.maxPasses) : 3;
|
|
4065
4069
|
const readinessCheckLabel = options.readinessCheckLabel ?? "Real-call profile history";
|
|
4066
4070
|
const fetchImpl = options.fetch ?? fetch;
|
|
4067
4071
|
const recoveryActionsHref = options.recoveryActionsHref ?? "/api/production-readiness/recovery-actions";
|
|
@@ -4103,70 +4107,84 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
4103
4107
|
actionCount: 0,
|
|
4104
4108
|
actions,
|
|
4105
4109
|
jobs: [],
|
|
4110
|
+
passes: 0,
|
|
4106
4111
|
ok: realCallProfileGate2?.status === "pass",
|
|
4107
4112
|
realCallProfileGate: realCallProfileGate2,
|
|
4108
4113
|
startFailures: []
|
|
4109
4114
|
};
|
|
4110
4115
|
}
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
return [];
|
|
4125
|
-
}
|
|
4126
|
-
return result.value.jobId ? [result.value] : [];
|
|
4127
|
-
});
|
|
4128
|
-
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
4129
|
-
{
|
|
4130
|
-
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
4131
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
4132
|
-
}
|
|
4133
|
-
] : []);
|
|
4134
|
-
const pollJob = async (jobId) => {
|
|
4135
|
-
const deadline = Date.now() + jobTimeoutMs;
|
|
4136
|
-
while (Date.now() < deadline) {
|
|
4137
|
-
const body = await fetchJson(resolveJobHref(jobId));
|
|
4138
|
-
const job = body.job;
|
|
4139
|
-
if (!job) {
|
|
4140
|
-
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
4116
|
+
const allJobs = [];
|
|
4117
|
+
const allStartFailures = [];
|
|
4118
|
+
let realCallProfileGate = null;
|
|
4119
|
+
let passes = 0;
|
|
4120
|
+
for (let pass = 1;pass <= maxPasses; pass += 1) {
|
|
4121
|
+
passes = pass;
|
|
4122
|
+
options.logger?.log(`Running ${String(actions.length)} real-call profile recovery action(s) in parallel (pass ${String(pass)}/${String(maxPasses)}).`);
|
|
4123
|
+
for (const action of actions) {
|
|
4124
|
+
options.logger?.log(`- ${describeVoiceRealCallProfileRecoveryLoopAction(action)}`);
|
|
4125
|
+
}
|
|
4126
|
+
const starts = await Promise.allSettled(actions.map(async (action) => {
|
|
4127
|
+
if (!action.href) {
|
|
4128
|
+
throw new Error("Recovery action is missing href.");
|
|
4141
4129
|
}
|
|
4142
|
-
|
|
4143
|
-
|
|
4130
|
+
const body = await fetchJson(action.href, { method: "POST" });
|
|
4131
|
+
return { action, ...body };
|
|
4132
|
+
}));
|
|
4133
|
+
const startedJobs = starts.flatMap((result) => {
|
|
4134
|
+
if (result.status === "rejected") {
|
|
4135
|
+
return [];
|
|
4144
4136
|
}
|
|
4145
|
-
|
|
4137
|
+
return result.value.jobId ? [result.value] : [];
|
|
4138
|
+
});
|
|
4139
|
+
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
4140
|
+
{
|
|
4141
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
4142
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
4143
|
+
}
|
|
4144
|
+
] : []);
|
|
4145
|
+
allStartFailures.push(...startFailures);
|
|
4146
|
+
const pollJob = async (jobId) => {
|
|
4147
|
+
const deadline = Date.now() + jobTimeoutMs;
|
|
4148
|
+
while (Date.now() < deadline) {
|
|
4149
|
+
const body = await fetchJson(resolveJobHref(jobId));
|
|
4150
|
+
const job = body.job;
|
|
4151
|
+
if (!job) {
|
|
4152
|
+
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
4153
|
+
}
|
|
4154
|
+
if (job.status === "pass" || job.status === "fail") {
|
|
4155
|
+
return job;
|
|
4156
|
+
}
|
|
4157
|
+
await sleepVoiceRealCallProfileRecoveryLoop(jobPollMs);
|
|
4158
|
+
}
|
|
4159
|
+
throw new Error(`Timed out waiting ${String(jobTimeoutMs)}ms for recovery job ${jobId}.`);
|
|
4160
|
+
};
|
|
4161
|
+
options.logger?.log(`Polling ${String(startedJobs.length)} recovery job(s) in parallel.`);
|
|
4162
|
+
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
4163
|
+
const jobs = jobResults.map((result, index) => ({
|
|
4164
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
4165
|
+
jobId: startedJobs[index]?.jobId,
|
|
4166
|
+
result: result.status === "fulfilled" ? result.value : {
|
|
4167
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
4168
|
+
status: "fail"
|
|
4169
|
+
}
|
|
4170
|
+
}));
|
|
4171
|
+
allJobs.push(...jobs);
|
|
4172
|
+
if (refreshHref !== false) {
|
|
4173
|
+
await fetchJson(refreshHref, { method: "POST" });
|
|
4146
4174
|
}
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
4151
|
-
const jobs = jobResults.map((result, index) => ({
|
|
4152
|
-
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
4153
|
-
jobId: startedJobs[index]?.jobId,
|
|
4154
|
-
result: result.status === "fulfilled" ? result.value : {
|
|
4155
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
4156
|
-
status: "fail"
|
|
4175
|
+
realCallProfileGate = await getGate(true);
|
|
4176
|
+
if (realCallProfileGate?.status === "pass") {
|
|
4177
|
+
break;
|
|
4157
4178
|
}
|
|
4158
|
-
}));
|
|
4159
|
-
if (refreshHref !== false) {
|
|
4160
|
-
await fetchJson(refreshHref, { method: "POST" });
|
|
4161
4179
|
}
|
|
4162
|
-
const realCallProfileGate = await getGate(true);
|
|
4163
4180
|
return {
|
|
4164
|
-
actionCount: actions.length,
|
|
4181
|
+
actionCount: actions.length * passes,
|
|
4165
4182
|
actions,
|
|
4166
|
-
jobs,
|
|
4167
|
-
|
|
4183
|
+
jobs: allJobs,
|
|
4184
|
+
passes,
|
|
4185
|
+
ok: allStartFailures.length === 0 && allJobs.every((job) => job.result.status === "pass") && realCallProfileGate?.status === "pass",
|
|
4168
4186
|
realCallProfileGate,
|
|
4169
|
-
startFailures
|
|
4187
|
+
startFailures: allStartFailures
|
|
4170
4188
|
};
|
|
4171
4189
|
};
|
|
4172
4190
|
var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|