@absolutejs/voice 0.0.22-beta.460 → 0.0.22-beta.463
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 +57 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +831 -618
- package/dist/productionReadiness.d.ts +17 -0
- package/dist/proofPack.d.ts +6 -1
- package/dist/proofTrends.d.ts +25 -0
- package/dist/react/index.js +57 -0
- package/dist/sessionObservability.d.ts +41 -0
- package/dist/vue/index.js +57 -0
- package/dist/vue/useVoiceReadinessFailures.d.ts +16 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16864,7 +16864,38 @@ var resolveRealCallEvidenceRuntimeReconnectReports = async (reports, options) =>
|
|
|
16864
16864
|
}
|
|
16865
16865
|
return Array.isArray(resolved) ? resolved : [resolved];
|
|
16866
16866
|
};
|
|
16867
|
+
var resolveRealCallEvidenceRuntimeSurfaceEvidence = async (source, options) => {
|
|
16868
|
+
const resolved = typeof source === "function" ? await source(options) : source;
|
|
16869
|
+
if (!resolved) {
|
|
16870
|
+
return [];
|
|
16871
|
+
}
|
|
16872
|
+
return Array.isArray(resolved) ? [...resolved] : [resolved];
|
|
16873
|
+
};
|
|
16874
|
+
var createRealCallEvidenceRuntimeSessionId = (prefix, generatedAt) => `${prefix}-${Date.parse(generatedAt) || Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
16875
|
+
var buildVoiceRealCallProfileEvidenceFromRuntimeSurface = (input, options) => {
|
|
16876
|
+
const evidence = Array.isArray(input) ? input : [input];
|
|
16877
|
+
return evidence.map((item) => {
|
|
16878
|
+
const generatedAt = item.generatedAt ?? (options.now ?? (() => new Date))().toISOString();
|
|
16879
|
+
return {
|
|
16880
|
+
...item,
|
|
16881
|
+
generatedAt,
|
|
16882
|
+
profileId: item.profileId ?? options.defaultProfileId,
|
|
16883
|
+
providers: item.providers ? [...item.providers] : undefined,
|
|
16884
|
+
sessionId: item.sessionId ?? createRealCallEvidenceRuntimeSessionId(options.defaultSessionPrefix, generatedAt),
|
|
16885
|
+
surfaces: [
|
|
16886
|
+
...new Set([...item.surfaces ?? [], ...options.defaultSurfaces])
|
|
16887
|
+
].sort()
|
|
16888
|
+
};
|
|
16889
|
+
});
|
|
16890
|
+
};
|
|
16891
|
+
var buildVoiceRealCallProfileEvidenceFromRuntimeProviderRoles = (input, options = {}) => buildVoiceRealCallProfileEvidenceFromRuntimeSurface(input, {
|
|
16892
|
+
defaultProfileId: options.defaultProfileId ?? "provider-role-evidence",
|
|
16893
|
+
defaultSessionPrefix: options.defaultSessionPrefix ?? "provider-role-evidence",
|
|
16894
|
+
defaultSurfaces: ["provider-path"],
|
|
16895
|
+
now: options.now
|
|
16896
|
+
});
|
|
16867
16897
|
var mergeRealCallEvidenceRuntimeOptions = (base, override = {}) => ({
|
|
16898
|
+
browserEvidence: override.browserEvidence ?? base.browserEvidence,
|
|
16868
16899
|
dedupe: override.dedupe ?? base.dedupe,
|
|
16869
16900
|
evidenceStore: override.evidenceStore ?? base.evidenceStore,
|
|
16870
16901
|
existingEvidenceLimit: override.existingEvidenceLimit ?? base.existingEvidenceLimit,
|
|
@@ -16873,6 +16904,8 @@ var mergeRealCallEvidenceRuntimeOptions = (base, override = {}) => ({
|
|
|
16873
16904
|
...override.history ?? {}
|
|
16874
16905
|
},
|
|
16875
16906
|
now: override.now ?? base.now,
|
|
16907
|
+
phoneEvidence: override.phoneEvidence ?? base.phoneEvidence,
|
|
16908
|
+
providerRoleEvidence: override.providerRoleEvidence ?? base.providerRoleEvidence,
|
|
16876
16909
|
reconnectEvidence: {
|
|
16877
16910
|
...base.reconnectEvidence ?? {},
|
|
16878
16911
|
...override.reconnectEvidence ?? {}
|
|
@@ -16921,6 +16954,30 @@ var buildRealCallEvidenceRuntimeReport = async (options, input = {}) => {
|
|
|
16921
16954
|
};
|
|
16922
16955
|
var collectVoiceRealCallEvidenceRuntimeEvidence = async (options) => {
|
|
16923
16956
|
const evidence = [];
|
|
16957
|
+
const browserEvidence = await resolveRealCallEvidenceRuntimeSurfaceEvidence(options.browserEvidence, options);
|
|
16958
|
+
if (browserEvidence.length > 0) {
|
|
16959
|
+
evidence.push(...buildVoiceRealCallProfileEvidenceFromRuntimeSurface(browserEvidence, {
|
|
16960
|
+
defaultProfileId: "browser-call",
|
|
16961
|
+
defaultSessionPrefix: "browser-call",
|
|
16962
|
+
defaultSurfaces: ["browser"],
|
|
16963
|
+
now: options.now
|
|
16964
|
+
}));
|
|
16965
|
+
}
|
|
16966
|
+
const phoneEvidence = await resolveRealCallEvidenceRuntimeSurfaceEvidence(options.phoneEvidence, options);
|
|
16967
|
+
if (phoneEvidence.length > 0) {
|
|
16968
|
+
evidence.push(...buildVoiceRealCallProfileEvidenceFromRuntimeSurface(phoneEvidence, {
|
|
16969
|
+
defaultProfileId: "phone-agent",
|
|
16970
|
+
defaultSessionPrefix: "phone-agent",
|
|
16971
|
+
defaultSurfaces: ["phone", "telephony"],
|
|
16972
|
+
now: options.now
|
|
16973
|
+
}));
|
|
16974
|
+
}
|
|
16975
|
+
const providerRoleEvidence = await resolveRealCallEvidenceRuntimeSurfaceEvidence(options.providerRoleEvidence, options);
|
|
16976
|
+
if (providerRoleEvidence.length > 0) {
|
|
16977
|
+
evidence.push(...buildVoiceRealCallProfileEvidenceFromRuntimeProviderRoles(providerRoleEvidence, {
|
|
16978
|
+
now: options.now
|
|
16979
|
+
}));
|
|
16980
|
+
}
|
|
16924
16981
|
if (options.traceStore) {
|
|
16925
16982
|
evidence.push(...buildVoiceRealCallProfileEvidenceFromTraceEvents(await options.traceStore.list({
|
|
16926
16983
|
limit: options.traceEvidence?.limit ?? 5000
|
|
@@ -22045,10 +22102,10 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
22045
22102
|
return routes;
|
|
22046
22103
|
};
|
|
22047
22104
|
// src/operationalStatus.ts
|
|
22048
|
-
import { Elysia as
|
|
22105
|
+
import { Elysia as Elysia47 } from "elysia";
|
|
22049
22106
|
|
|
22050
22107
|
// src/productionReadiness.ts
|
|
22051
|
-
import { Elysia as
|
|
22108
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
22052
22109
|
|
|
22053
22110
|
// src/handoffHealth.ts
|
|
22054
22111
|
import { Elysia as Elysia33 } from "elysia";
|
|
@@ -26620,188 +26677,516 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
26620
26677
|
return app;
|
|
26621
26678
|
};
|
|
26622
26679
|
|
|
26623
|
-
// src/
|
|
26680
|
+
// src/sessionObservability.ts
|
|
26624
26681
|
import { Elysia as Elysia42 } from "elysia";
|
|
26625
|
-
|
|
26626
|
-
|
|
26627
|
-
var
|
|
26628
|
-
|
|
26629
|
-
var STAGE_LABELS = {
|
|
26630
|
-
assistant_text_to_tts_send: "Assistant text to TTS send",
|
|
26631
|
-
barge_in_stop: "Barge-in stop latency",
|
|
26632
|
-
commit_to_assistant_text: "Commit to assistant text",
|
|
26633
|
-
final_to_commit: "Final transcript to commit",
|
|
26634
|
-
live_latency: "Browser live latency",
|
|
26635
|
-
provider_llm: "LLM provider latency",
|
|
26636
|
-
provider_stt: "STT provider latency",
|
|
26637
|
-
provider_tts: "TTS provider latency",
|
|
26638
|
-
speech_to_commit: "Speech detected to commit",
|
|
26639
|
-
tts_send_duration: "TTS send duration",
|
|
26640
|
-
tts_to_first_audio: "TTS to first audio"
|
|
26641
|
-
};
|
|
26642
|
-
var TRACE_TYPES = [
|
|
26643
|
-
"assistant.run",
|
|
26644
|
-
"client.barge_in",
|
|
26645
|
-
"client.live_latency",
|
|
26646
|
-
"turn.transcript",
|
|
26647
|
-
"turn_latency.stage"
|
|
26648
|
-
];
|
|
26649
|
-
var getNumber10 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
26650
|
-
var getString14 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
26651
|
-
var percentile5 = (values, percentileValue) => {
|
|
26652
|
-
if (values.length === 0) {
|
|
26653
|
-
return;
|
|
26654
|
-
}
|
|
26655
|
-
const sorted = [...values].sort((left, right) => left - right);
|
|
26656
|
-
const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil(percentileValue / 100 * sorted.length) - 1));
|
|
26657
|
-
return Math.round(sorted[index] ?? 0);
|
|
26658
|
-
};
|
|
26659
|
-
var average2 = (values) => values.length === 0 ? undefined : Math.round(values.reduce((total, value) => total + value, 0) / values.length);
|
|
26660
|
-
var resolveBudget = (stage, options) => ({
|
|
26661
|
-
failAfterMs: options.budgets?.[stage]?.failAfterMs ?? options.failAfterMs ?? DEFAULT_FAIL_AFTER_MS,
|
|
26662
|
-
warnAfterMs: options.budgets?.[stage]?.warnAfterMs ?? options.warnAfterMs ?? DEFAULT_WARN_AFTER_MS
|
|
26663
|
-
});
|
|
26664
|
-
var statusForLatency = (latencyMs, budget) => latencyMs > budget.failAfterMs ? "fail" : budget.warnAfterMs !== undefined && latencyMs > budget.warnAfterMs ? "warn" : "pass";
|
|
26665
|
-
var stageMeasurement = (input) => {
|
|
26666
|
-
if (input.latencyMs === undefined) {
|
|
26682
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26683
|
+
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
26684
|
+
var resolveHref = (href, sessionId) => {
|
|
26685
|
+
if (href === false) {
|
|
26667
26686
|
return;
|
|
26668
26687
|
}
|
|
26669
|
-
|
|
26670
|
-
|
|
26671
|
-
latencyMs: Math.max(0, Math.round(input.latencyMs)),
|
|
26672
|
-
label: STAGE_LABELS[input.stage],
|
|
26673
|
-
provider: input.provider,
|
|
26674
|
-
sessionId: input.sessionId,
|
|
26675
|
-
stage: input.stage,
|
|
26676
|
-
status: statusForLatency(Math.max(0, input.latencyMs), input.budget),
|
|
26677
|
-
turnId: input.turnId
|
|
26678
|
-
};
|
|
26679
|
-
};
|
|
26680
|
-
var providerStageForEvent = (event) => {
|
|
26681
|
-
if (event.type === "assistant.run") {
|
|
26682
|
-
return "provider_llm";
|
|
26683
|
-
}
|
|
26684
|
-
if (event.type === "turn.transcript") {
|
|
26685
|
-
return "provider_stt";
|
|
26686
|
-
}
|
|
26687
|
-
const kind = getString14(event.payload.providerKind) ?? getString14(event.payload.kind) ?? getString14(event.payload.lane);
|
|
26688
|
-
if (kind === "llm" || kind === "model") {
|
|
26689
|
-
return "provider_llm";
|
|
26690
|
-
}
|
|
26691
|
-
if (kind === "stt" || kind === "transcription") {
|
|
26692
|
-
return "provider_stt";
|
|
26688
|
+
if (typeof href === "function") {
|
|
26689
|
+
return href(sessionId);
|
|
26693
26690
|
}
|
|
26694
|
-
if (
|
|
26695
|
-
return "
|
|
26691
|
+
if (typeof href === "string") {
|
|
26692
|
+
return href.includes(":sessionId") ? href.replaceAll(":sessionId", encodeURIComponent(sessionId)) : `${href.replace(/\/$/, "")}/${encodeURIComponent(sessionId)}`;
|
|
26696
26693
|
}
|
|
26697
26694
|
return;
|
|
26698
26695
|
};
|
|
26699
|
-
var
|
|
26700
|
-
|
|
26701
|
-
const
|
|
26702
|
-
|
|
26703
|
-
|
|
26704
|
-
continue;
|
|
26696
|
+
var buildLinks = (options) => {
|
|
26697
|
+
const links = [];
|
|
26698
|
+
const add = (rel, label, href) => {
|
|
26699
|
+
if (href) {
|
|
26700
|
+
links.push({ href, label, rel });
|
|
26705
26701
|
}
|
|
26706
|
-
|
|
26707
|
-
|
|
26702
|
+
};
|
|
26703
|
+
add("operations-record", "Open operations record", resolveHref(options.operationsRecordHref, options.sessionId));
|
|
26704
|
+
add("trace-timeline", "Open trace timeline", resolveHref(options.traceTimelineHref, options.sessionId));
|
|
26705
|
+
add("call-debugger", "Open call debugger", resolveHref(options.callDebuggerHref, options.sessionId));
|
|
26706
|
+
add("incident-markdown", "Download incident Markdown", resolveHref(options.incidentMarkdownHref, options.sessionId));
|
|
26707
|
+
return [...links, ...options.customLinks ?? []];
|
|
26708
|
+
};
|
|
26709
|
+
var buildTurnWaterfalls = (record) => {
|
|
26710
|
+
const byTurn = new Map;
|
|
26711
|
+
const getTurn = (turnId) => {
|
|
26712
|
+
const existing = byTurn.get(turnId);
|
|
26713
|
+
if (existing) {
|
|
26714
|
+
return existing;
|
|
26715
|
+
}
|
|
26716
|
+
const turn = {
|
|
26717
|
+
assistantReplies: 0,
|
|
26718
|
+
errors: 0,
|
|
26719
|
+
providerDecisions: 0,
|
|
26720
|
+
stages: [],
|
|
26721
|
+
toolCalls: 0,
|
|
26722
|
+
transcripts: 0
|
|
26723
|
+
};
|
|
26724
|
+
byTurn.set(turnId, turn);
|
|
26725
|
+
return turn;
|
|
26726
|
+
};
|
|
26727
|
+
for (const event of record.timeline) {
|
|
26728
|
+
if (!event.turnId) {
|
|
26708
26729
|
continue;
|
|
26709
26730
|
}
|
|
26710
|
-
const
|
|
26711
|
-
|
|
26712
|
-
|
|
26713
|
-
|
|
26714
|
-
|
|
26731
|
+
const turn = getTurn(event.turnId);
|
|
26732
|
+
turn.stages.push({
|
|
26733
|
+
at: event.at,
|
|
26734
|
+
elapsedMs: event.elapsedMs,
|
|
26735
|
+
label: event.label,
|
|
26736
|
+
offsetMs: event.offsetMs,
|
|
26737
|
+
provider: event.provider,
|
|
26738
|
+
status: event.status,
|
|
26739
|
+
type: event.type
|
|
26740
|
+
});
|
|
26741
|
+
if (event.type === "turn.transcript") {
|
|
26742
|
+
turn.transcripts += 1;
|
|
26715
26743
|
}
|
|
26716
|
-
|
|
26717
|
-
|
|
26718
|
-
const measurements = [];
|
|
26719
|
-
for (const [key, stages] of grouped) {
|
|
26720
|
-
const [sessionId, turnId] = key.split(":");
|
|
26721
|
-
if (!sessionId || !turnId) {
|
|
26722
|
-
continue;
|
|
26744
|
+
if (event.type === "turn.assistant") {
|
|
26745
|
+
turn.assistantReplies += 1;
|
|
26723
26746
|
}
|
|
26724
|
-
|
|
26725
|
-
|
|
26726
|
-
|
|
26727
|
-
|
|
26728
|
-
|
|
26729
|
-
|
|
26730
|
-
|
|
26731
|
-
|
|
26732
|
-
{
|
|
26733
|
-
at: turnCommitted ?? 0,
|
|
26734
|
-
budget: resolveBudget("speech_to_commit", options),
|
|
26735
|
-
latencyMs: speechDetected === undefined || turnCommitted === undefined ? undefined : turnCommitted - speechDetected,
|
|
26736
|
-
required: true,
|
|
26737
|
-
sessionId,
|
|
26738
|
-
stage: "speech_to_commit",
|
|
26739
|
-
turnId
|
|
26740
|
-
},
|
|
26741
|
-
{
|
|
26742
|
-
at: turnCommitted ?? 0,
|
|
26743
|
-
budget: resolveBudget("final_to_commit", options),
|
|
26744
|
-
latencyMs: finalTranscript === undefined || turnCommitted === undefined ? undefined : turnCommitted - finalTranscript,
|
|
26745
|
-
required: true,
|
|
26746
|
-
sessionId,
|
|
26747
|
-
stage: "final_to_commit",
|
|
26748
|
-
turnId
|
|
26749
|
-
},
|
|
26750
|
-
{
|
|
26751
|
-
at: assistantTextStarted ?? 0,
|
|
26752
|
-
budget: resolveBudget("commit_to_assistant_text", options),
|
|
26753
|
-
latencyMs: turnCommitted === undefined || assistantTextStarted === undefined ? undefined : assistantTextStarted - turnCommitted,
|
|
26754
|
-
required: true,
|
|
26755
|
-
sessionId,
|
|
26756
|
-
stage: "commit_to_assistant_text",
|
|
26757
|
-
turnId
|
|
26758
|
-
},
|
|
26759
|
-
{
|
|
26760
|
-
at: ttsSendStarted ?? 0,
|
|
26761
|
-
budget: resolveBudget("assistant_text_to_tts_send", options),
|
|
26762
|
-
latencyMs: assistantTextStarted === undefined || ttsSendStarted === undefined ? undefined : ttsSendStarted - assistantTextStarted,
|
|
26763
|
-
required: true,
|
|
26764
|
-
sessionId,
|
|
26765
|
-
stage: "assistant_text_to_tts_send",
|
|
26766
|
-
turnId
|
|
26767
|
-
},
|
|
26768
|
-
{
|
|
26769
|
-
at: ttsSendCompleted ?? 0,
|
|
26770
|
-
budget: resolveBudget("tts_send_duration", options),
|
|
26771
|
-
latencyMs: ttsSendStarted === undefined || ttsSendCompleted === undefined ? undefined : ttsSendCompleted - ttsSendStarted,
|
|
26772
|
-
required: true,
|
|
26773
|
-
sessionId,
|
|
26774
|
-
stage: "tts_send_duration",
|
|
26775
|
-
turnId
|
|
26776
|
-
},
|
|
26777
|
-
{
|
|
26778
|
-
at: assistantAudioReceived ?? 0,
|
|
26779
|
-
budget: resolveBudget("tts_to_first_audio", options),
|
|
26780
|
-
latencyMs: ttsSendCompleted === undefined || assistantAudioReceived === undefined ? undefined : assistantAudioReceived - ttsSendCompleted,
|
|
26781
|
-
required: true,
|
|
26782
|
-
sessionId,
|
|
26783
|
-
stage: "tts_to_first_audio",
|
|
26784
|
-
turnId
|
|
26785
|
-
}
|
|
26786
|
-
];
|
|
26787
|
-
for (const candidate of candidates) {
|
|
26788
|
-
const measurement = stageMeasurement(candidate);
|
|
26789
|
-
if (measurement) {
|
|
26790
|
-
measurements.push(measurement);
|
|
26791
|
-
}
|
|
26747
|
+
if (event.type === "agent.tool") {
|
|
26748
|
+
turn.toolCalls += 1;
|
|
26749
|
+
}
|
|
26750
|
+
if (event.type === "provider.decision") {
|
|
26751
|
+
turn.providerDecisions += 1;
|
|
26752
|
+
}
|
|
26753
|
+
if (event.type === "session.error" || event.status === "error") {
|
|
26754
|
+
turn.errors += 1;
|
|
26792
26755
|
}
|
|
26793
26756
|
}
|
|
26794
|
-
|
|
26795
|
-
|
|
26796
|
-
|
|
26797
|
-
|
|
26798
|
-
|
|
26799
|
-
|
|
26800
|
-
|
|
26801
|
-
|
|
26802
|
-
|
|
26803
|
-
|
|
26804
|
-
|
|
26757
|
+
for (const transcript of record.transcript) {
|
|
26758
|
+
const turn = getTurn(transcript.id);
|
|
26759
|
+
turn.assistantReplies = Math.max(turn.assistantReplies, transcript.assistantReplies.length);
|
|
26760
|
+
turn.errors += transcript.errors.length;
|
|
26761
|
+
turn.transcripts = Math.max(turn.transcripts, transcript.transcripts.length);
|
|
26762
|
+
}
|
|
26763
|
+
return [...byTurn.entries()].map(([turnId, turn]) => {
|
|
26764
|
+
const startedAt = turn.stages[0]?.at;
|
|
26765
|
+
const endedAt = turn.stages.at(-1)?.at;
|
|
26766
|
+
return {
|
|
26767
|
+
assistantReplies: turn.assistantReplies,
|
|
26768
|
+
durationMs: startedAt !== undefined && endedAt !== undefined ? Math.max(0, endedAt - startedAt) : undefined,
|
|
26769
|
+
endedAt,
|
|
26770
|
+
errors: turn.errors,
|
|
26771
|
+
providerDecisions: turn.providerDecisions,
|
|
26772
|
+
stages: turn.stages,
|
|
26773
|
+
startedAt,
|
|
26774
|
+
toolCalls: turn.toolCalls,
|
|
26775
|
+
transcripts: turn.transcripts,
|
|
26776
|
+
turnId
|
|
26777
|
+
};
|
|
26778
|
+
}).sort((left, right) => (left.startedAt ?? 0) - (right.startedAt ?? 0));
|
|
26779
|
+
};
|
|
26780
|
+
var buildVoiceSessionObservabilityReport = async (options) => {
|
|
26781
|
+
const record = await buildVoiceOperationsRecord({
|
|
26782
|
+
audit: options.audit,
|
|
26783
|
+
evaluation: options.evaluation,
|
|
26784
|
+
events: options.events,
|
|
26785
|
+
integrationEvents: options.integrationEvents,
|
|
26786
|
+
redact: options.redact,
|
|
26787
|
+
reviews: options.reviews,
|
|
26788
|
+
sessionId: options.sessionId,
|
|
26789
|
+
store: options.store,
|
|
26790
|
+
tasks: options.tasks
|
|
26791
|
+
});
|
|
26792
|
+
const failureReplay = buildVoiceFailureReplay(record, {
|
|
26793
|
+
operationsRecordHref: resolveHref(options.operationsRecordHref, options.sessionId)
|
|
26794
|
+
});
|
|
26795
|
+
const incidentMarkdown = renderVoiceOperationsRecordIncidentMarkdown(record);
|
|
26796
|
+
const statuses = [
|
|
26797
|
+
record.status,
|
|
26798
|
+
failureReplay.status === "failed" ? "failed" : failureReplay.status === "degraded" ? "warning" : "healthy"
|
|
26799
|
+
];
|
|
26800
|
+
const status = statuses.includes("failed") ? "failed" : statuses.includes("warning") ? "warning" : "healthy";
|
|
26801
|
+
return {
|
|
26802
|
+
checkedAt: Date.now(),
|
|
26803
|
+
failureReplay,
|
|
26804
|
+
incidentMarkdown,
|
|
26805
|
+
links: buildLinks(options),
|
|
26806
|
+
record,
|
|
26807
|
+
sessionId: options.sessionId,
|
|
26808
|
+
status,
|
|
26809
|
+
summary: {
|
|
26810
|
+
durationMs: record.summary.callDurationMs,
|
|
26811
|
+
errors: record.summary.errorCount,
|
|
26812
|
+
events: record.summary.eventCount,
|
|
26813
|
+
fallbacks: record.providerDecisionSummary.fallbacks,
|
|
26814
|
+
guardrailBlocks: record.guardrails.blocked,
|
|
26815
|
+
handoffs: record.handoffs.length,
|
|
26816
|
+
providerRecoveryStatus: record.providerDecisionSummary.recoveryStatus,
|
|
26817
|
+
providers: record.providerDecisionSummary.providers,
|
|
26818
|
+
telephonyMediaEvents: record.telephonyMedia.total,
|
|
26819
|
+
toolCalls: record.tools.length,
|
|
26820
|
+
turns: record.summary.turnCount
|
|
26821
|
+
},
|
|
26822
|
+
turns: buildTurnWaterfalls(record)
|
|
26823
|
+
};
|
|
26824
|
+
};
|
|
26825
|
+
var renderLinks = (links) => links.length === 0 ? "" : `<div class="actions">${links.map((link) => `<a href="${escapeHtml40(link.href)}">${escapeHtml40(link.label)}</a>`).join("")}</div>`;
|
|
26826
|
+
var renderTurns = (turns) => turns.length === 0 ? '<p class="muted">No turn-level events recorded yet.</p>' : turns.map((turn) => `<article class="turn"><header><strong>${escapeHtml40(turn.turnId)}</strong><span>${formatMs4(turn.durationMs)}</span></header><dl><div><dt>Transcripts</dt><dd>${String(turn.transcripts)}</dd></div><div><dt>Assistant</dt><dd>${String(turn.assistantReplies)}</dd></div><div><dt>Tools</dt><dd>${String(turn.toolCalls)}</dd></div><div><dt>Providers</dt><dd>${String(turn.providerDecisions)}</dd></div><div><dt>Errors</dt><dd>${String(turn.errors)}</dd></div></dl><table><thead><tr><th>Offset</th><th>Type</th><th>Stage</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${turn.stages.map((stage) => `<tr><td>+${String(stage.offsetMs)}ms</td><td>${escapeHtml40(stage.type)}</td><td>${escapeHtml40(stage.label)}</td><td>${escapeHtml40(stage.provider ?? "")}</td><td>${escapeHtml40(stage.status ?? "")}</td><td>${formatMs4(stage.elapsedMs)}</td></tr>`).join("")}</tbody></table></article>`).join("");
|
|
26827
|
+
var renderVoiceSessionObservabilityMarkdown = (report) => `# Voice session observability: ${report.sessionId}
|
|
26828
|
+
|
|
26829
|
+
Status: ${report.status}
|
|
26830
|
+
|
|
26831
|
+
- Events: ${report.summary.events}
|
|
26832
|
+
- Turns: ${report.summary.turns}
|
|
26833
|
+
- Errors: ${report.summary.errors}
|
|
26834
|
+
- Duration: ${formatMs4(report.summary.durationMs)}
|
|
26835
|
+
- Providers: ${report.summary.providers.join(", ") || "none"}
|
|
26836
|
+
- Provider recovery: ${report.summary.providerRecoveryStatus}
|
|
26837
|
+
- Fallbacks: ${report.summary.fallbacks}
|
|
26838
|
+
- Tool calls: ${report.summary.toolCalls}
|
|
26839
|
+
- Handoffs: ${report.summary.handoffs}
|
|
26840
|
+
- Guardrail blocks: ${report.summary.guardrailBlocks}
|
|
26841
|
+
- Telephony media events: ${report.summary.telephonyMediaEvents}
|
|
26842
|
+
|
|
26843
|
+
## Links
|
|
26844
|
+
|
|
26845
|
+
${report.links.length ? report.links.map((link) => `- [${link.label}](${link.href})`).join(`
|
|
26846
|
+
`) : "- none"}
|
|
26847
|
+
|
|
26848
|
+
## Turn Waterfalls
|
|
26849
|
+
|
|
26850
|
+
${report.turns.length ? report.turns.map((turn) => `### ${turn.turnId}
|
|
26851
|
+
|
|
26852
|
+
- Duration: ${formatMs4(turn.durationMs)}
|
|
26853
|
+
- Transcripts: ${turn.transcripts}
|
|
26854
|
+
- Assistant replies: ${turn.assistantReplies}
|
|
26855
|
+
- Tool calls: ${turn.toolCalls}
|
|
26856
|
+
- Provider decisions: ${turn.providerDecisions}
|
|
26857
|
+
- Errors: ${turn.errors}
|
|
26858
|
+
|
|
26859
|
+
${turn.stages.map((stage) => `- +${stage.offsetMs}ms ${stage.type}: ${stage.label}${stage.provider ? ` (${stage.provider})` : ""}${stage.status ? ` [${stage.status}]` : ""}`).join(`
|
|
26860
|
+
`)}`).join(`
|
|
26861
|
+
|
|
26862
|
+
`) : "No turn-level events recorded."}
|
|
26863
|
+
|
|
26864
|
+
## Incident Handoff
|
|
26865
|
+
|
|
26866
|
+
${report.incidentMarkdown}`;
|
|
26867
|
+
var renderVoiceSessionObservabilityHTML = (report, options = {}) => `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml40(options.title ?? "Voice Session Observability")}</title><style>body{background:#0d1412;color:#f7f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #425046;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.actions{display:flex;flex-wrap:wrap;gap:10px;margin:18px 0}.actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:22px 0}.card,.turn,.incident{background:#17201c;border:1px solid #2e3c35;border-radius:20px;padding:16px}.card span,.muted,dt{color:#a8b4ad}.card strong{display:block;font-size:2rem}section{margin-top:30px}.turn{margin:16px 0}.turn header{align-items:center;display:flex;justify-content:space-between;gap:14px}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));margin:14px 0}dd{font-weight:900;margin:3px 0 0}table{border-collapse:collapse;margin-top:14px;width:100%}td,th{border-top:1px solid #2e3c35;padding:10px;text-align:left}pre{background:#08100d;border:1px solid #2e3c35;border-radius:16px;color:#d9f99d;overflow:auto;padding:14px}@media(max-width:760px){main{padding:20px}table{font-size:.9rem}}</style></head><body><main><header><p class="eyebrow">Session observability</p><h1>${escapeHtml40(report.sessionId)}</h1><p class="status ${escapeHtml40(report.status)}">${escapeHtml40(report.status)}</p>${renderLinks(report.links)}<p class="muted">One support/debug report across trace timeline, operations record, provider recovery, turn waterfalls, guardrails, tools, handoffs, failure replay, and incident handoff.</p></header><section class="grid"><article class="card"><span>Events</span><strong>${String(report.summary.events)}</strong></article><article class="card"><span>Turns</span><strong>${String(report.summary.turns)}</strong></article><article class="card"><span>Errors</span><strong>${String(report.summary.errors)}</strong></article><article class="card"><span>Duration</span><strong>${formatMs4(report.summary.durationMs)}</strong></article><article class="card"><span>Fallbacks</span><strong>${String(report.summary.fallbacks)}</strong></article><article class="card"><span>Tools</span><strong>${String(report.summary.toolCalls)}</strong></article><article class="card"><span>Handoffs</span><strong>${String(report.summary.handoffs)}</strong></article><article class="card"><span>Guardrails blocked</span><strong>${String(report.summary.guardrailBlocks)}</strong></article><article class="card"><span>Telephony media</span><strong>${String(report.summary.telephonyMediaEvents)}</strong></article></section><section><h2>Turn Waterfalls</h2>${renderTurns(report.turns)}</section><section class="incident"><h2>Incident Handoff</h2><pre><code>${escapeHtml40(report.incidentMarkdown)}</code></pre></section></main></body></html>`;
|
|
26868
|
+
var routeSessionId = (params) => typeof params.sessionId === "string" ? params.sessionId : "";
|
|
26869
|
+
var linkByRel = (links) => {
|
|
26870
|
+
const map = new Map;
|
|
26871
|
+
for (const link of links) {
|
|
26872
|
+
map.set(link.rel, true);
|
|
26873
|
+
}
|
|
26874
|
+
return (rel) => map.get(rel) ?? false;
|
|
26875
|
+
};
|
|
26876
|
+
var evaluateVoiceSessionObservabilityEvidence = (report, input = {}) => {
|
|
26877
|
+
const issues = [];
|
|
26878
|
+
const has = linkByRel(report.links);
|
|
26879
|
+
const status = report.status === "healthy" ? "pass" : report.status === "warning" ? "warn" : "fail";
|
|
26880
|
+
const turnsWithWaterfalls = report.turns.filter((turn) => turn.stages.length > 0).length;
|
|
26881
|
+
const stages = report.turns.reduce((total, turn) => total + turn.stages.length, 0);
|
|
26882
|
+
const providerDecisions = report.turns.reduce((total, turn) => total + turn.providerDecisions, 0);
|
|
26883
|
+
const toolCalls = report.turns.reduce((total, turn) => total + turn.toolCalls, 0);
|
|
26884
|
+
if (input.requireHealthy && report.status !== "healthy") {
|
|
26885
|
+
issues.push("Expected a healthy session observability report.");
|
|
26886
|
+
}
|
|
26887
|
+
if (input.minTurns !== undefined && report.summary.turns < input.minTurns) {
|
|
26888
|
+
issues.push(`Expected at least ${String(input.minTurns)} turn(s), found ${String(report.summary.turns)}.`);
|
|
26889
|
+
}
|
|
26890
|
+
if (input.minTurnWaterfalls !== undefined && turnsWithWaterfalls < input.minTurnWaterfalls) {
|
|
26891
|
+
issues.push(`Expected at least ${String(input.minTurnWaterfalls)} turn(s) with stage data, found ${String(turnsWithWaterfalls)}.`);
|
|
26892
|
+
}
|
|
26893
|
+
if (input.minStageCount !== undefined && stages < input.minStageCount) {
|
|
26894
|
+
issues.push(`Expected at least ${String(input.minStageCount)} turn stages, found ${String(stages)}.`);
|
|
26895
|
+
}
|
|
26896
|
+
if (input.minProviderDecisions !== undefined && providerDecisions < input.minProviderDecisions) {
|
|
26897
|
+
issues.push(`Expected at least ${String(input.minProviderDecisions)} provider decision stage(s), found ${String(providerDecisions)}.`);
|
|
26898
|
+
}
|
|
26899
|
+
if (input.minToolCalls !== undefined && toolCalls < input.minToolCalls) {
|
|
26900
|
+
issues.push(`Expected at least ${String(input.minToolCalls)} tool call stage(s), found ${String(toolCalls)}.`);
|
|
26901
|
+
}
|
|
26902
|
+
if (input.maxErrors !== undefined && report.summary.errors > input.maxErrors) {
|
|
26903
|
+
issues.push(`Expected at most ${String(input.maxErrors)} error(s), found ${String(report.summary.errors)}.`);
|
|
26904
|
+
}
|
|
26905
|
+
if (input.maxFallbacks !== undefined && report.summary.fallbacks > input.maxFallbacks) {
|
|
26906
|
+
issues.push(`Expected at most ${String(input.maxFallbacks)} fallback(s), found ${String(report.summary.fallbacks)}.`);
|
|
26907
|
+
}
|
|
26908
|
+
if (input.requireOperationsRecordLink && !has("operations-record")) {
|
|
26909
|
+
issues.push("Expected operations-record link in session observability evidence.");
|
|
26910
|
+
}
|
|
26911
|
+
if (input.requireTraceTimelineLink && !has("trace-timeline")) {
|
|
26912
|
+
issues.push("Expected trace-timeline link in session observability evidence.");
|
|
26913
|
+
}
|
|
26914
|
+
if (input.requireCallDebuggerLink && !has("call-debugger")) {
|
|
26915
|
+
issues.push("Expected call-debugger link in session observability evidence.");
|
|
26916
|
+
}
|
|
26917
|
+
if (input.requireIncidentMarkdownLink && !has("incident-markdown")) {
|
|
26918
|
+
issues.push("Expected incident-markdown link in session observability evidence.");
|
|
26919
|
+
}
|
|
26920
|
+
if (input.requireIncidentMarkdown && (!report.incidentMarkdown || report.incidentMarkdown.trim().length < 24 || !report.incidentMarkdown.toLowerCase().includes("incident handoff"))) {
|
|
26921
|
+
issues.push("Expected readable incident markdown payload.");
|
|
26922
|
+
}
|
|
26923
|
+
if (input.requireProviderRecoveryStatus !== undefined && (Array.isArray(input.requireProviderRecoveryStatus) ? input.requireProviderRecoveryStatus : [input.requireProviderRecoveryStatus]).indexOf(report.summary.providerRecoveryStatus) === -1) {
|
|
26924
|
+
issues.push(`Expected provider recovery status ${String(input.requireProviderRecoveryStatus)}, found ${report.summary.providerRecoveryStatus}.`);
|
|
26925
|
+
}
|
|
26926
|
+
return {
|
|
26927
|
+
checkedAt: Date.now(),
|
|
26928
|
+
issues,
|
|
26929
|
+
ok: issues.length === 0,
|
|
26930
|
+
status: issues.length > 0 ? status === "fail" ? "fail" : "warn" : status,
|
|
26931
|
+
summary: {
|
|
26932
|
+
incidentMarkdownLength: report.incidentMarkdown.length,
|
|
26933
|
+
providerDecisions,
|
|
26934
|
+
providerRecoveryStatus: report.summary.providerRecoveryStatus,
|
|
26935
|
+
reportStatus: report.status,
|
|
26936
|
+
stages,
|
|
26937
|
+
turns: report.turns.length,
|
|
26938
|
+
turnsWithWaterfalls,
|
|
26939
|
+
toolCalls,
|
|
26940
|
+
links: {
|
|
26941
|
+
callDebugger: has("call-debugger"),
|
|
26942
|
+
incidentMarkdown: has("incident-markdown"),
|
|
26943
|
+
operationsRecord: has("operations-record"),
|
|
26944
|
+
traceTimeline: has("trace-timeline")
|
|
26945
|
+
}
|
|
26946
|
+
}
|
|
26947
|
+
};
|
|
26948
|
+
};
|
|
26949
|
+
var assertVoiceSessionObservabilityEvidence = (report, input = {}) => {
|
|
26950
|
+
const assertion = evaluateVoiceSessionObservabilityEvidence(report, input);
|
|
26951
|
+
if (!assertion.ok) {
|
|
26952
|
+
throw new Error(`Voice session observability evidence assertion failed: ${assertion.issues.join(" ")}`);
|
|
26953
|
+
}
|
|
26954
|
+
return assertion;
|
|
26955
|
+
};
|
|
26956
|
+
var createVoiceSessionObservabilityRoutes = (options) => {
|
|
26957
|
+
const path = options.path ?? "/api/voice/session-observability/:sessionId";
|
|
26958
|
+
const htmlPath = options.htmlPath ?? "/voice/session-observability/:sessionId";
|
|
26959
|
+
const incidentPath = options.incidentPath ?? "/api/voice/session-observability/:sessionId/incident.md";
|
|
26960
|
+
const title = options.title ?? "AbsoluteJS Voice Session Observability";
|
|
26961
|
+
const routes = new Elysia42({
|
|
26962
|
+
name: options.name ?? "absolutejs-voice-session-observability"
|
|
26963
|
+
});
|
|
26964
|
+
const build = (sessionId) => buildVoiceSessionObservabilityReport({
|
|
26965
|
+
audit: options.audit,
|
|
26966
|
+
callDebuggerHref: options.callDebuggerHref,
|
|
26967
|
+
customLinks: options.customLinks,
|
|
26968
|
+
evaluation: options.evaluation,
|
|
26969
|
+
events: options.events,
|
|
26970
|
+
incidentMarkdownHref: options.incidentMarkdownHref ?? (incidentPath === false ? false : incidentPath),
|
|
26971
|
+
integrationEvents: options.integrationEvents,
|
|
26972
|
+
operationsRecordHref: options.operationsRecordHref,
|
|
26973
|
+
redact: options.redact,
|
|
26974
|
+
reviews: options.reviews,
|
|
26975
|
+
sessionId,
|
|
26976
|
+
store: options.store,
|
|
26977
|
+
tasks: options.tasks,
|
|
26978
|
+
traceTimelineHref: options.traceTimelineHref
|
|
26979
|
+
});
|
|
26980
|
+
routes.get(path, async ({ params }) => Response.json(await build(routeSessionId(params))));
|
|
26981
|
+
if (htmlPath !== false) {
|
|
26982
|
+
routes.get(htmlPath, async ({ params }) => {
|
|
26983
|
+
const report = await build(routeSessionId(params));
|
|
26984
|
+
const body = await (options.render ?? ((input) => renderVoiceSessionObservabilityHTML(input, { title })))(report);
|
|
26985
|
+
return new Response(body, {
|
|
26986
|
+
headers: {
|
|
26987
|
+
"content-type": "text/html; charset=utf-8",
|
|
26988
|
+
...options.headers
|
|
26989
|
+
}
|
|
26990
|
+
});
|
|
26991
|
+
});
|
|
26992
|
+
}
|
|
26993
|
+
if (incidentPath !== false) {
|
|
26994
|
+
routes.get(incidentPath, async ({ params }) => {
|
|
26995
|
+
const report = await build(routeSessionId(params));
|
|
26996
|
+
const body = await (options.renderIncidentMarkdown ?? renderVoiceSessionObservabilityMarkdown)(report);
|
|
26997
|
+
return new Response(body, {
|
|
26998
|
+
headers: {
|
|
26999
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
27000
|
+
...options.headers
|
|
27001
|
+
}
|
|
27002
|
+
});
|
|
27003
|
+
});
|
|
27004
|
+
}
|
|
27005
|
+
return routes;
|
|
27006
|
+
};
|
|
27007
|
+
|
|
27008
|
+
// src/opsRecovery.ts
|
|
27009
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
27010
|
+
|
|
27011
|
+
// src/latencySlo.ts
|
|
27012
|
+
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
27013
|
+
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
27014
|
+
var STAGE_LABELS = {
|
|
27015
|
+
assistant_text_to_tts_send: "Assistant text to TTS send",
|
|
27016
|
+
barge_in_stop: "Barge-in stop latency",
|
|
27017
|
+
commit_to_assistant_text: "Commit to assistant text",
|
|
27018
|
+
final_to_commit: "Final transcript to commit",
|
|
27019
|
+
live_latency: "Browser live latency",
|
|
27020
|
+
provider_llm: "LLM provider latency",
|
|
27021
|
+
provider_stt: "STT provider latency",
|
|
27022
|
+
provider_tts: "TTS provider latency",
|
|
27023
|
+
speech_to_commit: "Speech detected to commit",
|
|
27024
|
+
tts_send_duration: "TTS send duration",
|
|
27025
|
+
tts_to_first_audio: "TTS to first audio"
|
|
27026
|
+
};
|
|
27027
|
+
var TRACE_TYPES = [
|
|
27028
|
+
"assistant.run",
|
|
27029
|
+
"client.barge_in",
|
|
27030
|
+
"client.live_latency",
|
|
27031
|
+
"turn.transcript",
|
|
27032
|
+
"turn_latency.stage"
|
|
27033
|
+
];
|
|
27034
|
+
var getNumber10 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
27035
|
+
var getString14 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
27036
|
+
var percentile5 = (values, percentileValue) => {
|
|
27037
|
+
if (values.length === 0) {
|
|
27038
|
+
return;
|
|
27039
|
+
}
|
|
27040
|
+
const sorted = [...values].sort((left, right) => left - right);
|
|
27041
|
+
const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil(percentileValue / 100 * sorted.length) - 1));
|
|
27042
|
+
return Math.round(sorted[index] ?? 0);
|
|
27043
|
+
};
|
|
27044
|
+
var average2 = (values) => values.length === 0 ? undefined : Math.round(values.reduce((total, value) => total + value, 0) / values.length);
|
|
27045
|
+
var resolveBudget = (stage, options) => ({
|
|
27046
|
+
failAfterMs: options.budgets?.[stage]?.failAfterMs ?? options.failAfterMs ?? DEFAULT_FAIL_AFTER_MS,
|
|
27047
|
+
warnAfterMs: options.budgets?.[stage]?.warnAfterMs ?? options.warnAfterMs ?? DEFAULT_WARN_AFTER_MS
|
|
27048
|
+
});
|
|
27049
|
+
var statusForLatency = (latencyMs, budget) => latencyMs > budget.failAfterMs ? "fail" : budget.warnAfterMs !== undefined && latencyMs > budget.warnAfterMs ? "warn" : "pass";
|
|
27050
|
+
var stageMeasurement = (input) => {
|
|
27051
|
+
if (input.latencyMs === undefined) {
|
|
27052
|
+
return;
|
|
27053
|
+
}
|
|
27054
|
+
return {
|
|
27055
|
+
at: input.at,
|
|
27056
|
+
latencyMs: Math.max(0, Math.round(input.latencyMs)),
|
|
27057
|
+
label: STAGE_LABELS[input.stage],
|
|
27058
|
+
provider: input.provider,
|
|
27059
|
+
sessionId: input.sessionId,
|
|
27060
|
+
stage: input.stage,
|
|
27061
|
+
status: statusForLatency(Math.max(0, input.latencyMs), input.budget),
|
|
27062
|
+
turnId: input.turnId
|
|
27063
|
+
};
|
|
27064
|
+
};
|
|
27065
|
+
var providerStageForEvent = (event) => {
|
|
27066
|
+
if (event.type === "assistant.run") {
|
|
27067
|
+
return "provider_llm";
|
|
27068
|
+
}
|
|
27069
|
+
if (event.type === "turn.transcript") {
|
|
27070
|
+
return "provider_stt";
|
|
27071
|
+
}
|
|
27072
|
+
const kind = getString14(event.payload.providerKind) ?? getString14(event.payload.kind) ?? getString14(event.payload.lane);
|
|
27073
|
+
if (kind === "llm" || kind === "model") {
|
|
27074
|
+
return "provider_llm";
|
|
27075
|
+
}
|
|
27076
|
+
if (kind === "stt" || kind === "transcription") {
|
|
27077
|
+
return "provider_stt";
|
|
27078
|
+
}
|
|
27079
|
+
if (kind === "tts" || kind === "speech") {
|
|
27080
|
+
return "provider_tts";
|
|
27081
|
+
}
|
|
27082
|
+
return;
|
|
27083
|
+
};
|
|
27084
|
+
var eventElapsedMs2 = (event) => getNumber10(event.payload.elapsedMs) ?? getNumber10(event.payload.latencyMs) ?? getNumber10(event.payload.durationMs);
|
|
27085
|
+
var collectTraceStageMeasurements = (events, options) => {
|
|
27086
|
+
const grouped = new Map;
|
|
27087
|
+
for (const event of events) {
|
|
27088
|
+
if (event.type !== "turn_latency.stage" || !event.turnId) {
|
|
27089
|
+
continue;
|
|
27090
|
+
}
|
|
27091
|
+
const stage = getString14(event.payload.stage);
|
|
27092
|
+
if (!stage) {
|
|
27093
|
+
continue;
|
|
27094
|
+
}
|
|
27095
|
+
const key = `${event.sessionId}:${event.turnId}`;
|
|
27096
|
+
const stages = grouped.get(key) ?? new Map;
|
|
27097
|
+
const previous = stages.get(stage);
|
|
27098
|
+
if (!previous || event.at < previous.at) {
|
|
27099
|
+
stages.set(stage, event);
|
|
27100
|
+
}
|
|
27101
|
+
grouped.set(key, stages);
|
|
27102
|
+
}
|
|
27103
|
+
const measurements = [];
|
|
27104
|
+
for (const [key, stages] of grouped) {
|
|
27105
|
+
const [sessionId, turnId] = key.split(":");
|
|
27106
|
+
if (!sessionId || !turnId) {
|
|
27107
|
+
continue;
|
|
27108
|
+
}
|
|
27109
|
+
const speechDetected = stages.get("speech_detected")?.at;
|
|
27110
|
+
const finalTranscript = stages.get("final_transcript")?.at;
|
|
27111
|
+
const turnCommitted = stages.get("turn_committed")?.at;
|
|
27112
|
+
const assistantTextStarted = stages.get("assistant_text_started")?.at;
|
|
27113
|
+
const ttsSendStarted = stages.get("tts_send_started")?.at;
|
|
27114
|
+
const ttsSendCompleted = stages.get("tts_send_completed")?.at;
|
|
27115
|
+
const assistantAudioReceived = stages.get("assistant_audio_received")?.at;
|
|
27116
|
+
const candidates = [
|
|
27117
|
+
{
|
|
27118
|
+
at: turnCommitted ?? 0,
|
|
27119
|
+
budget: resolveBudget("speech_to_commit", options),
|
|
27120
|
+
latencyMs: speechDetected === undefined || turnCommitted === undefined ? undefined : turnCommitted - speechDetected,
|
|
27121
|
+
required: true,
|
|
27122
|
+
sessionId,
|
|
27123
|
+
stage: "speech_to_commit",
|
|
27124
|
+
turnId
|
|
27125
|
+
},
|
|
27126
|
+
{
|
|
27127
|
+
at: turnCommitted ?? 0,
|
|
27128
|
+
budget: resolveBudget("final_to_commit", options),
|
|
27129
|
+
latencyMs: finalTranscript === undefined || turnCommitted === undefined ? undefined : turnCommitted - finalTranscript,
|
|
27130
|
+
required: true,
|
|
27131
|
+
sessionId,
|
|
27132
|
+
stage: "final_to_commit",
|
|
27133
|
+
turnId
|
|
27134
|
+
},
|
|
27135
|
+
{
|
|
27136
|
+
at: assistantTextStarted ?? 0,
|
|
27137
|
+
budget: resolveBudget("commit_to_assistant_text", options),
|
|
27138
|
+
latencyMs: turnCommitted === undefined || assistantTextStarted === undefined ? undefined : assistantTextStarted - turnCommitted,
|
|
27139
|
+
required: true,
|
|
27140
|
+
sessionId,
|
|
27141
|
+
stage: "commit_to_assistant_text",
|
|
27142
|
+
turnId
|
|
27143
|
+
},
|
|
27144
|
+
{
|
|
27145
|
+
at: ttsSendStarted ?? 0,
|
|
27146
|
+
budget: resolveBudget("assistant_text_to_tts_send", options),
|
|
27147
|
+
latencyMs: assistantTextStarted === undefined || ttsSendStarted === undefined ? undefined : ttsSendStarted - assistantTextStarted,
|
|
27148
|
+
required: true,
|
|
27149
|
+
sessionId,
|
|
27150
|
+
stage: "assistant_text_to_tts_send",
|
|
27151
|
+
turnId
|
|
27152
|
+
},
|
|
27153
|
+
{
|
|
27154
|
+
at: ttsSendCompleted ?? 0,
|
|
27155
|
+
budget: resolveBudget("tts_send_duration", options),
|
|
27156
|
+
latencyMs: ttsSendStarted === undefined || ttsSendCompleted === undefined ? undefined : ttsSendCompleted - ttsSendStarted,
|
|
27157
|
+
required: true,
|
|
27158
|
+
sessionId,
|
|
27159
|
+
stage: "tts_send_duration",
|
|
27160
|
+
turnId
|
|
27161
|
+
},
|
|
27162
|
+
{
|
|
27163
|
+
at: assistantAudioReceived ?? 0,
|
|
27164
|
+
budget: resolveBudget("tts_to_first_audio", options),
|
|
27165
|
+
latencyMs: ttsSendCompleted === undefined || assistantAudioReceived === undefined ? undefined : assistantAudioReceived - ttsSendCompleted,
|
|
27166
|
+
required: true,
|
|
27167
|
+
sessionId,
|
|
27168
|
+
stage: "tts_to_first_audio",
|
|
27169
|
+
turnId
|
|
27170
|
+
}
|
|
27171
|
+
];
|
|
27172
|
+
for (const candidate of candidates) {
|
|
27173
|
+
const measurement = stageMeasurement(candidate);
|
|
27174
|
+
if (measurement) {
|
|
27175
|
+
measurements.push(measurement);
|
|
27176
|
+
}
|
|
27177
|
+
}
|
|
27178
|
+
}
|
|
27179
|
+
return measurements;
|
|
27180
|
+
};
|
|
27181
|
+
var collectDirectMeasurements = (events, options) => {
|
|
27182
|
+
const measurements = [];
|
|
27183
|
+
for (const event of events) {
|
|
27184
|
+
if (event.type === "client.live_latency") {
|
|
27185
|
+
const stage = "live_latency";
|
|
27186
|
+
const measurement = stageMeasurement({
|
|
27187
|
+
at: event.at,
|
|
27188
|
+
budget: resolveBudget(stage, options),
|
|
27189
|
+
latencyMs: eventElapsedMs2(event),
|
|
26805
27190
|
sessionId: event.sessionId,
|
|
26806
27191
|
stage,
|
|
26807
27192
|
turnId: event.turnId
|
|
@@ -26927,7 +27312,7 @@ None.
|
|
|
26927
27312
|
};
|
|
26928
27313
|
|
|
26929
27314
|
// src/opsRecovery.ts
|
|
26930
|
-
var
|
|
27315
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26931
27316
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
26932
27317
|
var hrefForSession = (value, sessionId) => {
|
|
26933
27318
|
if (typeof value === "function") {
|
|
@@ -27141,19 +27526,19 @@ ${failedSessions || "None."}
|
|
|
27141
27526
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
27142
27527
|
`;
|
|
27143
27528
|
};
|
|
27144
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
27529
|
+
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${escapeHtml41(label)}</span><strong>${String(summary.failed + summary.deadLettered)} failed</strong><small>${String(summary.pending)} pending \xB7 ${String(summary.retryEligible)} retry eligible \xB7 ${String(summary.total)} total</small></article>` : `<article><span>${escapeHtml41(label)}</span><strong>not configured</strong></article>`;
|
|
27145
27530
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
27146
27531
|
const title = options.title ?? "Voice Ops Recovery";
|
|
27147
|
-
const issues = report.issues.map((issue) => `<tr><td>${
|
|
27148
|
-
const providers = report.providers.providers.map((provider) => `<tr><td>${
|
|
27149
|
-
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${
|
|
27150
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27532
|
+
const issues = report.issues.map((issue) => `<tr><td>${escapeHtml41(issue.severity)}</td><td><code>${escapeHtml41(issue.code)}</code></td><td>${issue.href ? `<a href="${escapeHtml41(issue.href)}">${escapeHtml41(issue.label)}</a>` : escapeHtml41(issue.label)}</td><td>${escapeHtml41(String(issue.value ?? ""))}</td><td>${escapeHtml41(issue.detail ?? "")}</td></tr>`).join("");
|
|
27533
|
+
const providers = report.providers.providers.map((provider) => `<tr><td>${escapeHtml41(provider.provider)}</td><td>${escapeHtml41(provider.status)}</td><td>${String(provider.runCount)}</td><td>${String(provider.errorCount)}</td><td>${String(provider.fallbackCount)}</td><td>${escapeHtml41(provider.lastError ?? "")}</td></tr>`).join("");
|
|
27534
|
+
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${escapeHtml41(session.operationsRecordHref)}">${escapeHtml41(session.sessionId)}</a>` : escapeHtml41(session.sessionId)}${session.provider ? ` via ${escapeHtml41(session.provider)}` : ""}${session.error ? `: ${escapeHtml41(session.error)}` : ""}</li>`).join("");
|
|
27535
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml41(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#f8fafc;color:#172033;margin:2rem;line-height:1.45}main{max-width:1180px;margin:auto}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.75rem;margin:1rem 0}article{background:white;border:1px solid #dbe3ef;border-radius:14px;padding:1rem;box-shadow:0 10px 28px rgba(15,23,42,.05)}article span{display:block;color:#64748b;font-size:.85rem}article strong{display:block;font-size:1.5rem;margin:.2rem 0}article small{color:#64748b}table{border-collapse:collapse;width:100%;background:white;border:1px solid #dbe3ef;border-radius:14px;overflow:hidden}th,td{border-bottom:1px solid #e2e8f0;padding:.7rem;text-align:left;vertical-align:top}code{font-size:.85em}.status{display:inline-flex;border-radius:999px;padding:.35rem .7rem;background:${report.status === "fail" ? "#fee2e2" : report.status === "warn" ? "#fef3c7" : "#dcfce7"};color:${report.status === "fail" ? "#991b1b" : report.status === "warn" ? "#92400e" : "#166534"};font-weight:700}</style></head><body><main><h1>${escapeHtml41(title)}</h1><p><span class="status">${escapeHtml41(report.status)}</span> Checked ${escapeHtml41(new Date(report.checkedAt).toLocaleString())}</p><section class="grid"><article><span>Recovered fallbacks</span><strong>${String(report.providers.recoveredFallbacks)}</strong></article><article><span>Unresolved providers</span><strong>${String(report.providers.unresolvedFailures)}</strong></article><article><span>Operator interventions</span><strong>${String(report.interventions.total)}</strong></article><article><span>Latency status</span><strong>${escapeHtml41(report.latency?.status ?? "disabled")}</strong></article>${renderDeliverySummary("Audit delivery", report.auditDeliveries)}${renderDeliverySummary("Trace delivery", report.traceDeliveries)}${renderDeliverySummary("Handoff delivery", report.handoffDeliveries)}</section><h2>Issues</h2><table><thead><tr><th>Severity</th><th>Code</th><th>Label</th><th>Value</th><th>Detail</th></tr></thead><tbody>${issues || '<tr><td colspan="5">No recovery issues.</td></tr>'}</tbody></table><h2>Providers</h2><table><thead><tr><th>Provider</th><th>Status</th><th>Runs</th><th>Errors</th><th>Fallbacks</th><th>Last error</th></tr></thead><tbody>${providers || '<tr><td colspan="6">No provider activity.</td></tr>'}</tbody></table><h2>Failed Sessions</h2><ul>${failedSessions || "<li>None.</li>"}</ul></main></body></html>`;
|
|
27151
27536
|
};
|
|
27152
27537
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
27153
27538
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
27154
27539
|
const htmlPath = options.htmlPath === undefined ? "/ops-recovery" : options.htmlPath;
|
|
27155
27540
|
const markdownPath = options.markdownPath === undefined ? `${path}.md` : options.markdownPath;
|
|
27156
|
-
const routes = new
|
|
27541
|
+
const routes = new Elysia43({
|
|
27157
27542
|
name: options.name ?? "absolutejs-voice-ops-recovery"
|
|
27158
27543
|
}).get(path, async () => buildVoiceOpsRecoveryReport(options));
|
|
27159
27544
|
if (htmlPath) {
|
|
@@ -27183,8 +27568,8 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
|
27183
27568
|
};
|
|
27184
27569
|
|
|
27185
27570
|
// src/incidentTimeline.ts
|
|
27186
|
-
import { Elysia as
|
|
27187
|
-
var
|
|
27571
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
27572
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27188
27573
|
var resolveValue = async (value) => typeof value === "function" ? await value() : value;
|
|
27189
27574
|
var linkForSession = (link, sessionId) => {
|
|
27190
27575
|
if (!link || !sessionId) {
|
|
@@ -27305,8 +27690,8 @@ var buildVoiceIncidentRecoveryOutcomeReport = async (options) => {
|
|
|
27305
27690
|
};
|
|
27306
27691
|
var renderVoiceIncidentRecoveryOutcomeHTML = (report, options = {}) => {
|
|
27307
27692
|
const title = options.title ?? "AbsoluteJS Voice Incident Recovery Outcomes";
|
|
27308
|
-
const rows = report.entries.map((entry) => `<article class="${
|
|
27309
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27693
|
+
const rows = report.entries.map((entry) => `<article class="${escapeHtml42(entry.outcome)}"><span>${escapeHtml42(entry.outcome.toUpperCase())}</span><h2>${escapeHtml42(entry.actionId)}</h2><p>${escapeHtml42(new Date(entry.at).toLocaleString())}</p><strong>${escapeHtml42(entry.beforeStatus ?? "unknown")} -> ${escapeHtml42(entry.afterStatus ?? "unknown")}</strong>${entry.detail ? `<p>${escapeHtml42(entry.detail)}</p>` : ""}</article>`).join("");
|
|
27694
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml42(title)}</title><style>body{background:#10120d;color:#fbf4df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,article{background:#181711;border:1px solid #39301d;border-radius:24px;padding:20px}.hero{margin-bottom:16px}h1{font-size:clamp(2rem,6vw,4.5rem);line-height:.95}.summary{display:flex;flex-wrap:wrap;gap:10px}.summary span{border:1px solid #4a3f23;border-radius:999px;padding:8px 12px}section{display:grid;gap:12px}article.improved{border-color:rgba(34,197,94,.65)}article.failed,article.regressed{border-color:rgba(239,68,68,.8)}article.unchanged{border-color:rgba(245,158,11,.7)}article span{color:#fcd34d;font-weight:900;letter-spacing:.08em}article strong{display:block;font-size:1.4rem;margin:.5rem 0}p{color:#cfc5a8}</style></head><body><main><section class="hero"><span>Recovery proof</span><h1>${escapeHtml42(title)}</h1><div class="summary"><span>${String(report.improved)} improved</span><span>${String(report.unchanged)} unchanged</span><span>${String(report.regressed)} regressed</span><span>${String(report.failed)} failed</span><span>${String(report.total)} total</span></div></section><section>${rows || "<p>No incident recovery actions have been recorded.</p>"}</section></main></body></html>`;
|
|
27310
27695
|
};
|
|
27311
27696
|
var buildVoiceIncidentRecoveryOutcomeReadinessCheck = (report, options = {}) => {
|
|
27312
27697
|
const failOnFailed = options.failOnFailed ?? true;
|
|
@@ -27503,8 +27888,8 @@ ${rows || "| n/a | 0 | 0 | 0 | 0 | 0 | n/a | n/a |"}
|
|
|
27503
27888
|
};
|
|
27504
27889
|
var renderVoiceIncidentRecoveryTrendHTML = (report, options = {}) => {
|
|
27505
27890
|
const title = options.title ?? "AbsoluteJS Voice Incident Recovery Trend";
|
|
27506
|
-
const rows = report.cycles.map((cycle) => `<tr><td>${
|
|
27507
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27891
|
+
const rows = report.cycles.map((cycle) => `<tr><td>${escapeHtml42(new Date(cycle.checkedAt).toLocaleString())}</td><td>${String(cycle.total)}</td><td>${String(cycle.improved)}</td><td>${String(cycle.unchanged)}</td><td>${String(cycle.regressed)}</td><td>${String(cycle.failed)}</td><td>${escapeHtml42(percent(cycle.improvementRate))}</td><td>${escapeHtml42(percent(cycle.regressionRate))}</td></tr>`).join("");
|
|
27892
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml42(title)}</title><style>body{background:#10120d;color:#fbf4df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero,table{background:#181711;border:1px solid #39301d;border-radius:24px}.hero{margin-bottom:16px;padding:24px}h1{font-size:clamp(2rem,6vw,4.5rem);line-height:.95}.summary{display:flex;flex-wrap:wrap;gap:10px}.summary span{border:1px solid #4a3f23;border-radius:999px;padding:8px 12px}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #39301d;padding:12px;text-align:left}.pass{color:#86efac}.warn,.empty{color:#fcd34d}.fail{color:#fca5a5}p{color:#cfc5a8}</style></head><body><main><section class="hero"><span>Recovery trend</span><h1>${escapeHtml42(title)}</h1><p class="${escapeHtml42(report.status)}">Status: ${escapeHtml42(report.status)}</p><div class="summary"><span>${String(report.summary.cycles)} cycles</span><span>${String(report.summary.total)} actions</span><span>${escapeHtml42(percent(report.summary.improvementRate))} improved</span><span>${escapeHtml42(percent(report.summary.regressionRate))} regressed</span><span>${escapeHtml42(percent(report.trend.improvementRateDelta))} improvement delta</span></div></section><table><thead><tr><th>Checked at</th><th>Total</th><th>Improved</th><th>Unchanged</th><th>Regressed</th><th>Failed</th><th>Improve %</th><th>Regress %</th></tr></thead><tbody>${rows || '<tr><td colspan="8">No recovery outcome history has been recorded.</td></tr>'}</tbody></table></main></body></html>`;
|
|
27508
27893
|
};
|
|
27509
27894
|
var pushOperationalStatusEvents = (events, report, links) => {
|
|
27510
27895
|
if (!report) {
|
|
@@ -27730,22 +28115,22 @@ ${report.actions.map((action) => `- ${action.method ?? "GET"} ${action.id}: ${ac
|
|
|
27730
28115
|
var renderVoiceIncidentTimelineHTML = (report, options = {}) => {
|
|
27731
28116
|
const title = options.title ?? "AbsoluteJS Voice Incident Timeline";
|
|
27732
28117
|
const actionPath = options.actionPath ?? "/api/voice/incident-timeline/actions";
|
|
27733
|
-
const events = report.events.map((event) => `<article class="${
|
|
27734
|
-
<span>${
|
|
27735
|
-
<h2>${
|
|
27736
|
-
<p>${
|
|
27737
|
-
${event.value === undefined ? "" : `<strong>${
|
|
27738
|
-
${event.detail ? `<p>${
|
|
27739
|
-
<div>${event.href ? `<a href="${
|
|
28118
|
+
const events = report.events.map((event) => `<article class="${escapeHtml42(event.severity)}">
|
|
28119
|
+
<span>${escapeHtml42(event.severity.toUpperCase())} / ${escapeHtml42(event.category)}</span>
|
|
28120
|
+
<h2>${escapeHtml42(event.label)}</h2>
|
|
28121
|
+
<p>${escapeHtml42(new Date(event.at).toLocaleString())}${event.sessionId ? ` \xB7 session ${escapeHtml42(event.sessionId)}` : ""}</p>
|
|
28122
|
+
${event.value === undefined ? "" : `<strong>${escapeHtml42(String(event.value))}</strong>`}
|
|
28123
|
+
${event.detail ? `<p>${escapeHtml42(event.detail)}</p>` : ""}
|
|
28124
|
+
<div>${event.href ? `<a href="${escapeHtml42(event.href)}">Open source</a>` : ""}${event.action?.href ? `<a href="${escapeHtml42(event.action.href)}">${escapeHtml42(event.action.label)}</a>` : ""}</div>
|
|
27740
28125
|
</article>`).join("");
|
|
27741
28126
|
const actions = report.actions.map((action) => {
|
|
27742
|
-
const label =
|
|
27743
|
-
const detail = action.detail ? `<p>${
|
|
27744
|
-
const href = action.href ? `<a href="${
|
|
27745
|
-
const control = action.method === "POST" ? `<button type="button" data-voice-incident-action="${
|
|
27746
|
-
return `<article class="action"><span>${
|
|
28127
|
+
const label = escapeHtml42(action.label);
|
|
28128
|
+
const detail = action.detail ? `<p>${escapeHtml42(action.detail)}</p>` : "";
|
|
28129
|
+
const href = action.href ? `<a href="${escapeHtml42(action.href)}">Open target</a>` : "";
|
|
28130
|
+
const control = action.method === "POST" ? `<button type="button" data-voice-incident-action="${escapeHtml42(action.id)}" ${action.disabled ? "disabled" : ""}>${label}</button>` : href;
|
|
28131
|
+
return `<article class="action"><span>${escapeHtml42(action.method ?? "GET")}</span><h2>${label}</h2>${detail}<div>${control}${href && action.method === "POST" ? href : ""}</div></article>`;
|
|
27747
28132
|
}).join("");
|
|
27748
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
28133
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml42(title)}</title><style>body{background:#11110d;color:#faf4df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero{background:linear-gradient(135deg,rgba(248,113,113,.2),rgba(245,158,11,.13),rgba(34,197,94,.12));border:1px solid #39301d;border-radius:30px;margin-bottom:18px;padding:28px}.eyebrow{color:#fcd34d;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #575030;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.pass{border-color:rgba(34,197,94,.65)}.status.warn{border-color:rgba(245,158,11,.75)}.status.fail{border-color:rgba(239,68,68,.85)}.grid{display:grid;gap:14px}.actions{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:0 0 18px}.summary{display:flex;flex-wrap:wrap;gap:10px}.summary span{background:#181711;border:1px solid #39301d;border-radius:999px;padding:8px 12px}article{background:#181711;border:1px solid #39301d;border-radius:22px;padding:18px}article.critical{border-color:rgba(239,68,68,.85)}article.warn{border-color:rgba(245,158,11,.75)}article.info{border-color:rgba(34,197,94,.55)}article.action{border-color:#5b4a22}article span{color:#fcd34d;font-size:.78rem;font-weight:900;letter-spacing:.08em}article h2{margin:.35rem 0}.muted,article p{color:#cfc5a8}article strong{display:block;font-size:1.3rem;margin:.5rem 0}a{color:#fde68a;margin-right:12px}button{background:#fcd34d;border:0;border-radius:999px;color:#171307;cursor:pointer;font-weight:900;padding:10px 14px}button:disabled{cursor:not-allowed;opacity:.55}</style></head><body><main><section class="hero"><p class="eyebrow">Operational triage</p><h1>${escapeHtml42(title)}</h1><p class="status ${escapeHtml42(report.status)}">Overall: ${escapeHtml42(report.status.toUpperCase())}</p><p class="muted">Generated ${escapeHtml42(new Date(report.generatedAt).toLocaleString())}</p><div class="summary"><span>${String(report.summary.critical)} critical</span><span>${String(report.summary.warn)} warn</span><span>${String(report.summary.info)} info</span><span>${String(report.summary.total)} total</span></div></section><h2>Recovery actions</h2><section class="actions">${actions || '<article class="action"><span>NONE</span><h2>No recovery actions</h2><p>No executable actions are available for this report.</p></article>'}</section><h2>Timeline</h2><section class="grid">${events || '<article class="info"><span>INFO</span><h2>No incident events</h2><p>No non-pass operational events were found in this window.</p></article>'}</section></main><script>const voiceIncidentActionPath=${JSON.stringify(actionPath)};document.querySelectorAll("[data-voice-incident-action]").forEach((button)=>{button.addEventListener("click",async()=>{const id=button.getAttribute("data-voice-incident-action");if(!id)return;button.disabled=true;const original=button.textContent;button.textContent="Running...";try{const response=await fetch(voiceIncidentActionPath+"/"+encodeURIComponent(id),{method:"POST"});button.textContent=response.ok?"Done":"Failed";if(response.ok)setTimeout(()=>location.reload(),700)}catch{button.textContent="Failed"}finally{setTimeout(()=>{button.disabled=false;button.textContent=original},1600)}})});</script></body></html>`;
|
|
27749
28134
|
};
|
|
27750
28135
|
var createVoiceIncidentTimelineRoutes = (options) => {
|
|
27751
28136
|
const path = options.path ?? "/api/voice/incident-timeline";
|
|
@@ -27765,7 +28150,7 @@ var createVoiceIncidentTimelineRoutes = (options) => {
|
|
|
27765
28150
|
})
|
|
27766
28151
|
]);
|
|
27767
28152
|
};
|
|
27768
|
-
const routes = new
|
|
28153
|
+
const routes = new Elysia44({
|
|
27769
28154
|
name: options.name ?? "absolutejs-voice-incident-timeline"
|
|
27770
28155
|
}).get(path, async () => {
|
|
27771
28156
|
const report = await buildVoiceIncidentTimelineReport(options);
|
|
@@ -27957,7 +28342,7 @@ var createVoiceIncidentTimelineRoutes = (options) => {
|
|
|
27957
28342
|
};
|
|
27958
28343
|
|
|
27959
28344
|
// src/observabilityExport.ts
|
|
27960
|
-
import { Elysia as
|
|
28345
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
27961
28346
|
import { Database as Database4 } from "bun:sqlite";
|
|
27962
28347
|
import { createHash } from "crypto";
|
|
27963
28348
|
import { mkdir as mkdir2, readFile, stat, unlink } from "fs/promises";
|
|
@@ -28622,7 +29007,7 @@ var createVoiceObservabilityExportReplayRoutes = (options) => {
|
|
|
28622
29007
|
...options.headers ?? {}
|
|
28623
29008
|
};
|
|
28624
29009
|
const buildReport = () => resolveVoiceObservabilityExportReplayReport(options.source);
|
|
28625
|
-
const app = new
|
|
29010
|
+
const app = new Elysia45({
|
|
28626
29011
|
name: options.name ?? "absolute-voice-observability-export-replay"
|
|
28627
29012
|
});
|
|
28628
29013
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -29488,7 +29873,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
29488
29873
|
artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
|
|
29489
29874
|
}
|
|
29490
29875
|
});
|
|
29491
|
-
const app = new
|
|
29876
|
+
const app = new Elysia45({
|
|
29492
29877
|
name: options.name ?? "absolute-voice-observability-export"
|
|
29493
29878
|
});
|
|
29494
29879
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -29595,7 +29980,7 @@ var buildVoiceReadinessRecoveryActions = (input, options = {}) => {
|
|
|
29595
29980
|
sourceChecks: sourceChecks.length
|
|
29596
29981
|
};
|
|
29597
29982
|
};
|
|
29598
|
-
var
|
|
29983
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29599
29984
|
var formatVoiceProofFreshnessDuration = (valueMs) => {
|
|
29600
29985
|
if (valueMs < 1000) {
|
|
29601
29986
|
return `${Math.max(0, Math.round(valueMs))}ms`;
|
|
@@ -29795,6 +30180,7 @@ var readinessGateCodes = {
|
|
|
29795
30180
|
"Reconnect recovery contracts": "voice.readiness.reconnect_contracts",
|
|
29796
30181
|
"Routing evidence": "voice.readiness.routing_evidence",
|
|
29797
30182
|
"Session health": "voice.readiness.session_health",
|
|
30183
|
+
"Session observability evidence": "voice.readiness.session_observability_evidence",
|
|
29798
30184
|
"Trace sink delivery": "voice.readiness.trace_sink_delivery"
|
|
29799
30185
|
};
|
|
29800
30186
|
var readinessGateCodeForCheck = (check) => readinessGateCodes[check.label] ?? `voice.readiness.${check.label.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "")}`;
|
|
@@ -29960,6 +30346,18 @@ var resolveMonitoringNotifierDelivery = async (options, input) => {
|
|
|
29960
30346
|
}
|
|
29961
30347
|
return typeof options.monitoringNotifierDelivery === "function" ? await options.monitoringNotifierDelivery(input) : options.monitoringNotifierDelivery;
|
|
29962
30348
|
};
|
|
30349
|
+
var resolveSessionObservability = async (options, input) => {
|
|
30350
|
+
if (options.sessionObservability === false || options.sessionObservability === undefined) {
|
|
30351
|
+
return;
|
|
30352
|
+
}
|
|
30353
|
+
return typeof options.sessionObservability === "function" ? await options.sessionObservability(input) : options.sessionObservability;
|
|
30354
|
+
};
|
|
30355
|
+
var resolveSessionObservabilityEvidence = async (options, input) => {
|
|
30356
|
+
if (options.sessionObservabilityEvidence === false || options.sessionObservabilityEvidence === undefined) {
|
|
30357
|
+
return;
|
|
30358
|
+
}
|
|
30359
|
+
return typeof options.sessionObservabilityEvidence === "function" ? await options.sessionObservabilityEvidence(input) : options.sessionObservabilityEvidence;
|
|
30360
|
+
};
|
|
29963
30361
|
var resolveMediaPipeline = async (options, input) => {
|
|
29964
30362
|
if (options.mediaPipeline === false || options.mediaPipeline === undefined) {
|
|
29965
30363
|
return;
|
|
@@ -30481,6 +30879,8 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30481
30879
|
mediaPipeline,
|
|
30482
30880
|
browserMedia,
|
|
30483
30881
|
telephonyMedia,
|
|
30882
|
+
sessionObservability,
|
|
30883
|
+
sessionObservabilityEvidence,
|
|
30484
30884
|
telephonyWebhookSecurity,
|
|
30485
30885
|
reconnectContracts,
|
|
30486
30886
|
bargeInReports,
|
|
@@ -30530,6 +30930,8 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30530
30930
|
time("mediaPipeline", () => resolveMediaPipeline(options, { query, request })),
|
|
30531
30931
|
time("browserMedia", () => resolveBrowserMedia(options, { query, request })),
|
|
30532
30932
|
time("telephonyMedia", () => resolveTelephonyMedia(options, { query, request })),
|
|
30933
|
+
time("sessionObservability", () => resolveSessionObservability(options, { query, request })),
|
|
30934
|
+
time("sessionObservabilityEvidence", () => resolveSessionObservabilityEvidence(options, { query, request })),
|
|
30533
30935
|
time("telephonyWebhookSecurity", () => resolveTelephonyWebhookSecurity(options, { query, request })),
|
|
30534
30936
|
time("reconnectContracts", () => resolveReconnectContracts(options, { query, request })),
|
|
30535
30937
|
time("bargeInReports", () => resolveBargeInReports(options, { query, request })),
|
|
@@ -30573,6 +30975,15 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30573
30975
|
warnWhenEmpty: options.incidentRecoveryTrendSLO?.warnWhenEmpty,
|
|
30574
30976
|
mode: options.incidentRecoveryTrendSLO?.mode
|
|
30575
30977
|
}) : undefined;
|
|
30978
|
+
const sessionObservabilityEvidenceSummary = sessionObservability ? evaluateVoiceSessionObservabilityEvidence(sessionObservability, sessionObservabilityEvidence ?? {}) : undefined;
|
|
30979
|
+
const sessionObservabilitySummary = sessionObservability && sessionObservabilityEvidenceSummary ? {
|
|
30980
|
+
failed: sessionObservabilityEvidenceSummary.status === "fail" ? 1 : 0,
|
|
30981
|
+
passed: sessionObservabilityEvidenceSummary.status === "pass" ? 1 : 0,
|
|
30982
|
+
status: sessionObservabilityEvidenceSummary.status,
|
|
30983
|
+
total: 1,
|
|
30984
|
+
warnings: sessionObservabilityEvidenceSummary.status === "warn" ? 1 : 0
|
|
30985
|
+
} : undefined;
|
|
30986
|
+
const proofSource = (...keys) => keys.map((key) => proofSources?.[key]).find((source) => source !== undefined);
|
|
30576
30987
|
const checks = [
|
|
30577
30988
|
{
|
|
30578
30989
|
detail: quality.status === "pass" ? "Quality gates are passing." : "Quality gates need attention.",
|
|
@@ -30693,6 +31104,23 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30693
31104
|
}
|
|
30694
31105
|
] : []
|
|
30695
31106
|
},
|
|
31107
|
+
...sessionObservability && sessionObservabilitySummary ? [
|
|
31108
|
+
{
|
|
31109
|
+
detail: sessionObservabilitySummary.status === "pass" ? `Session observability is healthy with ${sessionObservabilityEvidenceSummary?.summary.turnsWithWaterfalls ?? 0} turn(s) containing waterfall stages and ${sessionObservabilityEvidenceSummary?.summary.providerDecisions ?? 0} provider decision stage(s).` : `${sessionObservabilityEvidenceSummary?.issues.join("; ") ?? "Session observability has unresolved issues."}`,
|
|
31110
|
+
href: options.links?.sessionObservability ?? "/voice/session-observability",
|
|
31111
|
+
label: "Session observability evidence",
|
|
31112
|
+
proofSource: proofSource("sessionObservability", "sessionObservability"),
|
|
31113
|
+
status: sessionObservabilitySummary.status,
|
|
31114
|
+
value: `${sessionObservabilitySummary.passed}/${sessionObservabilitySummary.total}`,
|
|
31115
|
+
actions: sessionObservabilitySummary.status === "pass" ? [] : [
|
|
31116
|
+
{
|
|
31117
|
+
description: "Open session observability report and address missing turns, provider decisions, tool calls, links, and incident markdown coverage.",
|
|
31118
|
+
href: options.links?.sessionObservability ?? "/voice/session-observability",
|
|
31119
|
+
label: "Open session observability"
|
|
31120
|
+
}
|
|
31121
|
+
]
|
|
31122
|
+
}
|
|
31123
|
+
] : [],
|
|
30696
31124
|
{
|
|
30697
31125
|
detail: routingEvents.length > 0 ? `${routingSessions.length} session(s) have provider routing evidence.` : "No provider routing traces are recorded yet.",
|
|
30698
31126
|
href: options.links?.resilience ?? "/resilience",
|
|
@@ -30709,7 +31137,6 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30709
31137
|
}
|
|
30710
31138
|
];
|
|
30711
31139
|
checks.push(...additionalChecks);
|
|
30712
|
-
const proofSource = (...keys) => keys.map((key) => proofSources?.[key]).find((source) => source !== undefined);
|
|
30713
31140
|
const calibratedThresholdActions = () => options.links?.sloReadinessThresholds ? [
|
|
30714
31141
|
{
|
|
30715
31142
|
description: "Open the calibrated thresholds currently driving this readiness gate.",
|
|
@@ -31556,6 +31983,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
31556
31983
|
profileSwitchLiveDecisions: "/voice/profile-switch-live-decisions",
|
|
31557
31984
|
profileSwitchPolicy: "/voice/profile-switch-policy",
|
|
31558
31985
|
profileSwitchReadiness: "/voice/profile-switch-readiness",
|
|
31986
|
+
sessionObservability: "/voice/session-observability",
|
|
31559
31987
|
telephonyMedia: "/voice/telephony-media",
|
|
31560
31988
|
telephonyWebhookSecurity: "/api/voice/telephony/webhook-security",
|
|
31561
31989
|
providerContracts: "/provider-contracts",
|
|
@@ -31626,6 +32054,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
31626
32054
|
providerRoutingContracts: providerRoutingContractSummary,
|
|
31627
32055
|
providerSlo: providerSloSummary,
|
|
31628
32056
|
reconnectContracts: reconnectContractSummary,
|
|
32057
|
+
sessionObservability: sessionObservabilitySummary,
|
|
31629
32058
|
quality: {
|
|
31630
32059
|
status: quality.status
|
|
31631
32060
|
},
|
|
@@ -31644,25 +32073,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
31644
32073
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
31645
32074
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
31646
32075
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
31647
|
-
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${
|
|
31648
|
-
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${
|
|
32076
|
+
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${escapeHtml43(report.links.sloReadinessThresholds)}">Open Calibration -> Active Readiness Gate</a> to inspect the thresholds currently driving calibrated provider, latency, interruption, reconnect, and monitoring gates.</p>` : "";
|
|
32077
|
+
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml43(report.profile.name)}</h2><p>${escapeHtml43(report.profile.description)}</p><p>${escapeHtml43(report.profile.purpose)}</p><div class="profile-surfaces">${report.profile.surfaces.map((surface) => `<article class="${surface.configured ? "pass" : "warn"}"><span>${surface.configured ? "CONFIGURED" : "EXPECTED"}</span><strong>${surface.href ? `<a href="${escapeHtml43(surface.href)}">${escapeHtml43(surface.label)}</a>` : escapeHtml43(surface.label)}</strong></article>`).join("")}</div></section>` : "";
|
|
31649
32078
|
const checks = report.checks.map((check, index) => {
|
|
31650
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
31651
|
-
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${
|
|
31652
|
-
return `<article class="check ${
|
|
32079
|
+
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml43(action.href)}">${escapeHtml43(action.label)}</button>` : `<a href="${escapeHtml43(action.href)}">${escapeHtml43(action.label)}</a>`).join("");
|
|
32080
|
+
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${escapeHtml43(check.status)}: observed ${escapeHtml43(String(check.gateExplanation.observed ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml43(check.gateExplanation.unit)}` : ""}; threshold ${escapeHtml43(String(check.gateExplanation.threshold ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml43(check.gateExplanation.unit)}` : ""}. ${escapeHtml43(check.gateExplanation.remediation)} ${check.gateExplanation.sourceHref ? `<a href="${escapeHtml43(check.gateExplanation.sourceHref)}">Open threshold source</a>` : ""}</p>` : "";
|
|
32081
|
+
return `<article class="check ${escapeHtml43(check.status)}">
|
|
31653
32082
|
<div>
|
|
31654
|
-
<span>${
|
|
31655
|
-
<h2>${
|
|
31656
|
-
${check.detail ? `<p>${
|
|
32083
|
+
<span>${escapeHtml43(check.status.toUpperCase())}</span>
|
|
32084
|
+
<h2>${escapeHtml43(check.label)}</h2>
|
|
32085
|
+
${check.detail ? `<p>${escapeHtml43(check.detail)}</p>` : ""}
|
|
31657
32086
|
${explanation}
|
|
31658
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
32087
|
+
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml43(check.proofSource.href)}">${escapeHtml43(check.proofSource.sourceLabel)}</a>` : escapeHtml43(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml43(check.proofSource.detail)}` : ""}</p>` : ""}
|
|
31659
32088
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
31660
32089
|
</div>
|
|
31661
|
-
<strong>${
|
|
31662
|
-
${check.href ? `<a href="${
|
|
32090
|
+
<strong>${escapeHtml43(String(check.value ?? check.status))}</strong>
|
|
32091
|
+
${check.href ? `<a href="${escapeHtml43(check.href)}">Open surface</a>` : ""}
|
|
31663
32092
|
</article>`;
|
|
31664
32093
|
}).join("");
|
|
31665
|
-
const snippet =
|
|
32094
|
+
const snippet = escapeHtml43(`createVoiceProductionReadinessRoutes({
|
|
31666
32095
|
htmlPath: '/production-readiness',
|
|
31667
32096
|
path: '/api/production-readiness',
|
|
31668
32097
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -31678,13 +32107,13 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
31678
32107
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
31679
32108
|
store: traceStore
|
|
31680
32109
|
});`);
|
|
31681
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32110
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml43(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero,.primitive,.profile{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.primitive,.profile{background:#111722}.primitive{border-color:#3a3f2d}.eyebrow{color:#fbbf24;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{display:inline-flex;border:1px solid #3f3f46;border-radius:999px;padding:8px 12px}.primitive code{color:#fde68a}.primitive p{color:#c8ccd3;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#0b0f16;border:1px solid #2c3440;border-radius:18px;color:#fef3c7;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.check.pass,.profile-surfaces .pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.warn,.profile-surfaces .warn{border-color:rgba(245,158,11,.65)}.status.fail,.check.fail{border-color:rgba(239,68,68,.75)}.checks{display:grid;gap:14px}.check{align-items:center;background:#141922;border:1px solid #26313d;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.check span,.profile-surfaces span{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p,.profile p{color:#b9c0c8;margin:.2rem 0 0}.check .proof-source{color:#f9d77e;font-weight:800}.check .gate-explanation{background:#0b0f16;border:1px solid #2c3440;border-radius:14px;color:#fef3c7;margin-top:10px;padding:10px}.check strong{font-size:1.5rem}.profile-surfaces{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin-top:16px}.profile-surfaces article{background:#141922;border:1px solid #26313d;border-radius:16px;padding:14px}.profile-surfaces strong{display:block;margin-top:6px}.actions{display:flex;flex-wrap:wrap;gap:10px}.check a,a{color:#fbbf24}button{background:#fbbf24;border:0;border-radius:999px;color:#111827;cursor:pointer;font-weight:800;padding:9px 12px}button:disabled{cursor:wait;opacity:.65}@media(max-width:760px){main{padding:20px}.check{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted readiness</p><h1>${escapeHtml43(title)}</h1><p>One deployable pass/fail report for quality gates, provider failover, session health, handoffs, routing evidence, and optional carrier readiness.</p><p class="status ${escapeHtml43(report.status)}">Overall: ${escapeHtml43(report.status.toUpperCase())}</p><p>Checked ${escapeHtml43(new Date(report.checkedAt).toLocaleString())}</p>${thresholdLink}</section>${profile}<section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProductionReadinessRoutes(...)</code> builds this deploy gate</h2><p>Mount one package primitive to expose JSON readiness, HTML readiness, and a machine-readable gate route. Feed it the proof stores and contract reports your app already owns.</p><pre><code>${snippet}</code></pre></section><section class="checks">${checks}</section></main><script>document.querySelectorAll("[data-readiness-action]").forEach((button)=>{button.addEventListener("click",async()=>{const url=button.getAttribute("data-action-url");if(!url)return;button.disabled=true;const original=button.textContent;button.textContent="Running...";try{const response=await fetch(url,{method:"POST"});button.textContent=response.ok?"Done. Reloading...":"Failed";if(response.ok)setTimeout(()=>location.reload(),500)}catch{button.textContent="Failed"}finally{setTimeout(()=>{button.disabled=false;button.textContent=original},1500)}})});</script></body></html>`;
|
|
31682
32111
|
};
|
|
31683
32112
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
31684
32113
|
const path = options.path ?? "/api/production-readiness";
|
|
31685
32114
|
const gatePath = options.gatePath === undefined ? "/api/production-readiness/gate" : options.gatePath;
|
|
31686
32115
|
const htmlPath = options.htmlPath ?? "/production-readiness";
|
|
31687
|
-
const routes = new
|
|
32116
|
+
const routes = new Elysia46({
|
|
31688
32117
|
name: options.name ?? "absolutejs-voice-production-readiness"
|
|
31689
32118
|
});
|
|
31690
32119
|
let cachedReport;
|
|
@@ -31756,7 +32185,7 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
31756
32185
|
};
|
|
31757
32186
|
|
|
31758
32187
|
// src/operationalStatus.ts
|
|
31759
|
-
var
|
|
32188
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31760
32189
|
var resolveValue2 = async (value) => typeof value === "function" ? await value() : value;
|
|
31761
32190
|
var isDeliveryRuntime = (value) => Boolean(value && typeof value === "object" && "isRunning" in value && "summarize" in value);
|
|
31762
32191
|
var worstStatus3 = (statuses) => statuses.includes("fail") ? "fail" : statuses.includes("warn") ? "warn" : "pass";
|
|
@@ -31826,19 +32255,19 @@ var buildVoiceOperationalStatusReport = async (options) => {
|
|
|
31826
32255
|
};
|
|
31827
32256
|
var renderVoiceOperationalStatusHTML = (report, options = {}) => {
|
|
31828
32257
|
const title = options.title ?? "AbsoluteJS Voice Operational Status";
|
|
31829
|
-
const checks = report.checks.map((check) => `<article class="${
|
|
31830
|
-
<span>${
|
|
31831
|
-
<h2>${
|
|
31832
|
-
<strong>${
|
|
31833
|
-
${check.detail ? `<p>${
|
|
31834
|
-
${check.href ? `<a href="${
|
|
32258
|
+
const checks = report.checks.map((check) => `<article class="${escapeHtml44(check.status)}">
|
|
32259
|
+
<span>${escapeHtml44(check.status.toUpperCase())}</span>
|
|
32260
|
+
<h2>${escapeHtml44(check.label)}</h2>
|
|
32261
|
+
<strong>${escapeHtml44(String(check.value ?? check.status))}</strong>
|
|
32262
|
+
${check.detail ? `<p>${escapeHtml44(check.detail)}</p>` : ""}
|
|
32263
|
+
${check.href ? `<a href="${escapeHtml44(check.href)}">Open surface</a>` : ""}
|
|
31835
32264
|
</article>`).join("");
|
|
31836
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32265
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml44(title)}</title><style>body{background:#10130f;color:#f8f3df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1040px;padding:32px}.hero{background:linear-gradient(135deg,rgba(132,204,22,.18),rgba(14,165,233,.13));border:1px solid #2c3a28;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#bef264;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}article{background:#171d15;border:1px solid #2c3a28;border-radius:22px;padding:18px}article.pass{border-color:rgba(34,197,94,.65)}article.warn{border-color:rgba(245,158,11,.75)}article.fail{border-color:rgba(239,68,68,.85)}article span{color:#bef264;font-size:.78rem;font-weight:900;letter-spacing:.08em}article.warn span{color:#fbbf24}article.fail span{color:#fca5a5}article strong{display:block;font-size:1.6rem;margin:.4rem 0}article p{color:#c5ceb9}a{color:#bef264}</style></head><body><main><section class="hero"><p class="eyebrow">Operational status</p><h1>${escapeHtml44(title)}</h1><p class="status ${escapeHtml44(report.status)}">Overall: ${escapeHtml44(report.status.toUpperCase())}</p><p>${String(report.summary.pass)}/${String(report.summary.total)} checks passing. Checked ${escapeHtml44(new Date(report.checkedAt).toLocaleString())}.</p></section><section class="grid">${checks || '<article class="pass"><span>PASS</span><h2>No operational checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
|
|
31837
32266
|
};
|
|
31838
32267
|
var createVoiceOperationalStatusRoutes = (options) => {
|
|
31839
32268
|
const path = options.path ?? "/api/voice/operational-status";
|
|
31840
32269
|
const htmlPath = options.htmlPath === undefined ? "/voice/operational-status" : options.htmlPath;
|
|
31841
|
-
const routes = new
|
|
32270
|
+
const routes = new Elysia47({
|
|
31842
32271
|
name: options.name ?? "absolutejs-voice-operational-status"
|
|
31843
32272
|
}).get(path, async () => {
|
|
31844
32273
|
const report = await buildVoiceOperationalStatusReport(options);
|
|
@@ -31865,7 +32294,7 @@ var createVoiceOperationalStatusRoutes = (options) => {
|
|
|
31865
32294
|
return routes;
|
|
31866
32295
|
};
|
|
31867
32296
|
// src/dataControl.ts
|
|
31868
|
-
import { Elysia as
|
|
32297
|
+
import { Elysia as Elysia48 } from "elysia";
|
|
31869
32298
|
var voiceComplianceRedactionDefaults = {
|
|
31870
32299
|
keys: [
|
|
31871
32300
|
"apiKey",
|
|
@@ -32104,7 +32533,7 @@ var parseRetentionScopes = (value) => {
|
|
|
32104
32533
|
const allowed = new Set(allRetentionScopes);
|
|
32105
32534
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
32106
32535
|
};
|
|
32107
|
-
var
|
|
32536
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32108
32537
|
var buildStorageSurfaces = (options) => [
|
|
32109
32538
|
{
|
|
32110
32539
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -32341,12 +32770,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
32341
32770
|
zeroRetentionAvailable: true
|
|
32342
32771
|
};
|
|
32343
32772
|
};
|
|
32344
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
32773
|
+
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${escapeHtml45(scope.scope)}</td><td>${scope.scannedCount}</td><td>${scope.deletedCount}</td><td>${escapeHtml45(scope.skippedReason ?? "")}</td><td><code>${escapeHtml45(scope.deletedIds.join(", "))}</code></td></tr>`).join("");
|
|
32345
32774
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
32346
32775
|
const title = options.title ?? "Voice Data Control";
|
|
32347
|
-
const storageRows = report.storage.map((surface) => `<tr><td>${
|
|
32348
|
-
const keyRows = report.providerKeys.map((key) => `<tr><td>${
|
|
32349
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
32776
|
+
const storageRows = report.storage.map((surface) => `<tr><td>${escapeHtml45(surface.name)}</td><td>${surface.configured ? "Configured" : "Missing"}</td><td>${escapeHtml45(surface.control)}</td><td>${surface.selfHosted ? "Yes" : "No"}</td></tr>`).join("");
|
|
32777
|
+
const keyRows = report.providerKeys.map((key) => `<tr><td>${escapeHtml45(key.name)}</td><td><code>${escapeHtml45(key.env ?? "n/a")}</code></td><td>${key.required ? "Required" : "Optional"}</td><td>${escapeHtml45(key.recommendation)}</td></tr>`).join("");
|
|
32778
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml45(title)}</title><style>body{background:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1120px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml45(title)}</h1><p>Self-hosted data-control proof for retention, redaction, audit export, deletion planning, customer-owned storage, and provider key handling.</p><section class="summary"><div class="card"><strong>Redaction</strong><br>${report.redaction.enabled ? "enabled" : "disabled"}</div><div class="card"><strong>Retention dry-run deletes</strong><br>${report.retentionPlan.deletedCount}</div><div class="card"><strong>Audit export events</strong><br>${report.auditExport?.events.length ?? 0}</div><div class="card"><strong>Zero retention recipe</strong><br>${report.zeroRetentionAvailable ? "available" : "missing"}</div></section><h2>Customer-Owned Storage</h2><table><thead><tr><th>Surface</th><th>Status</th><th>Control</th><th>Self-hosted</th></tr></thead><tbody>${storageRows}</tbody></table><h2>Retention Plan</h2><table><thead><tr><th>Scope</th><th>Scanned</th><th>Would delete</th><th>Skipped</th><th>Ids</th></tr></thead><tbody>${renderDataRetentionReportRows(report.retentionPlan)}</tbody></table><h2>Provider Keys</h2><table><thead><tr><th>Provider</th><th>Env</th><th>Required</th><th>Recommendation</th></tr></thead><tbody>${keyRows}</tbody></table><p><a href="./data-control/audit.md">Redacted audit Markdown</a> \xB7 <a href="./data-control/audit.html">Redacted audit HTML</a></p></main></body></html>`;
|
|
32350
32779
|
};
|
|
32351
32780
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
32352
32781
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -32404,7 +32833,7 @@ var parseRetentionPolicyBody = (body, options, dryRun) => {
|
|
|
32404
32833
|
var createVoiceDataControlRoutes = (options) => {
|
|
32405
32834
|
const path = options.path ?? "/data-control";
|
|
32406
32835
|
const title = options.title ?? "AbsoluteJS Voice Data Control";
|
|
32407
|
-
const routes = new
|
|
32836
|
+
const routes = new Elysia48({
|
|
32408
32837
|
name: options.name ?? "absolutejs-voice-data-control"
|
|
32409
32838
|
});
|
|
32410
32839
|
routes.get(path, async ({ query }) => {
|
|
@@ -32480,10 +32909,10 @@ var createVoiceDataControlRoutes = (options) => {
|
|
|
32480
32909
|
return routes;
|
|
32481
32910
|
};
|
|
32482
32911
|
// src/evalRoutes.ts
|
|
32483
|
-
import { Elysia as
|
|
32912
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
32484
32913
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
32485
32914
|
import { dirname as dirname2 } from "path";
|
|
32486
|
-
var
|
|
32915
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32487
32916
|
var rate4 = (count, total) => count / Math.max(1, total);
|
|
32488
32917
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
32489
32918
|
var getString18 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -32814,7 +33243,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
32814
33243
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
32815
33244
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
32816
33245
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
32817
|
-
const snippet =
|
|
33246
|
+
const snippet = escapeHtml46(`app.use(
|
|
32818
33247
|
createVoiceEvalRoutes({
|
|
32819
33248
|
path: '/evals',
|
|
32820
33249
|
store: traceStore,
|
|
@@ -32835,48 +33264,48 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
32835
33264
|
};
|
|
32836
33265
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
32837
33266
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
32838
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
32839
|
-
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${
|
|
33267
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml46(link.href)}">${escapeHtml46(link.label)}</a>`).join("")}</nav>` : "";
|
|
33268
|
+
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml46(bucket.key)}</td><td>${bucket.total}</td><td>${bucket.passed}</td><td>${bucket.failed}</td></tr>`).join("") : '<tr><td colspan="4">No eval buckets yet.</td></tr>';
|
|
32840
33269
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
32841
33270
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
32842
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
32843
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
33271
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml46(session.operationsRecordHref)}">${escapeHtml46(session.sessionId)}</a>` : escapeHtml46(session.sessionId);
|
|
33272
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml46(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml46(formatTime(session.endedAt))}</td><td>${escapeHtml46(failedMetrics || "none")}</td></tr>`;
|
|
32844
33273
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
32845
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33274
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml46(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{color:#166534}.fail{color:#991b1b}.status.pass{background:#dcfce7}.status.fail{background:#fee2e2}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,.primitive{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3;margin:1rem 0}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}table{border-collapse:collapse;background:white;width:100%;margin:1rem 0 2rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml46(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}<h2>Trend</h2><table><thead><tr><th>Day</th><th>Total</th><th>Passed</th><th>Failed</th></tr></thead><tbody>${trend}</tbody></table><h2>Session Eval Results</h2><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Last event</th><th>Failed metrics</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
|
|
32846
33275
|
};
|
|
32847
33276
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
32848
33277
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
32849
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
32850
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
32851
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
32852
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
32853
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33278
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml46(link.href)}">${escapeHtml46(link.label)}</a>`).join("")}</nav>` : "";
|
|
33279
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml46(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
33280
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml46(id)}</li>`).join("") : "<li>none</li>";
|
|
33281
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml46(id)}</li>`).join("") : "<li>none</li>";
|
|
33282
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml46(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1000px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{background:#dcfce7;color:#166534}.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}section{background:white;border:1px solid #e7e5e4;border-radius:1rem;margin:1rem 0;padding:1rem}</style></head><body><main>${links}<h1>${escapeHtml46(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml46(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml46(formatPercent(comparison.current.passRate))}</strong></article><article class="card"><span>Failed delta</span><strong>${comparison.deltas.failed}</strong></article><article class="card"><span>Pass rate delta</span><strong>${escapeHtml46(formatPercent(comparison.deltas.passRate))}</strong></article></div><section><h2>Regression Reasons</h2><ul>${reasons}</ul></section><section><h2>New Failed Sessions</h2><ul>${newFailures}</ul></section><section><h2>Recovered Sessions</h2><ul>${recovered}</ul></section></main></body></html>`;
|
|
32854
33283
|
};
|
|
32855
33284
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
32856
33285
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
32857
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
33286
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml46(link.href)}">${escapeHtml46(link.label)}</a>`).join("")}</nav>` : "";
|
|
32858
33287
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
32859
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
33288
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml46(issue)}</li>`).join("")}</ul>` : "";
|
|
32860
33289
|
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => {
|
|
32861
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
32862
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
33290
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml46(session.operationsRecordHref)}">${escapeHtml46(session.sessionId)}</a>` : escapeHtml46(session.sessionId);
|
|
33291
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml46(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml46(session.issues.join(", ") || "none")}</td></tr>`;
|
|
32863
33292
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
32864
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
33293
|
+
return `<section class="scenario ${scenario.status}"><h2>${escapeHtml46(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml46(scenario.description)}</p>` : ""}<p class="status ${scenario.status}">${scenario.status}</p><p>${scenario.passed} passed, ${scenario.failed} failed, ${scenario.matchedSessions} matched.</p>${scenarioIssues}<table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Issues</th></tr></thead><tbody>${sessions}</tbody></table></section>`;
|
|
32865
33294
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
32866
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33295
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml46(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml46(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}${scenarios}</main></body></html>`;
|
|
32867
33296
|
};
|
|
32868
33297
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
32869
33298
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
32870
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
33299
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml46(link.href)}">${escapeHtml46(link.label)}</a>`).join("")}</nav>` : "";
|
|
32871
33300
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
32872
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
32873
|
-
return `<section class="${fixture.status}"><h2>${
|
|
33301
|
+
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml46(scenario.label)}</td><td>${escapeHtml46(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml46([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
|
|
33302
|
+
return `<section class="${fixture.status}"><h2>${escapeHtml46(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml46(fixture.description)}</p>` : ""}<p class="status ${fixture.status}">${fixture.status}</p><table><thead><tr><th>Scenario</th><th>Status</th><th>Sessions</th><th>Issues</th></tr></thead><tbody>${scenarios}</tbody></table></section>`;
|
|
32874
33303
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
32875
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33304
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml46(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml46(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${renderVoiceEvalPrimitiveCopy()}${fixtures}</main></body></html>`;
|
|
32876
33305
|
};
|
|
32877
33306
|
var createVoiceEvalRoutes = (options) => {
|
|
32878
33307
|
const path = options.path ?? "/evals";
|
|
32879
|
-
const routes = new
|
|
33308
|
+
const routes = new Elysia49({
|
|
32880
33309
|
name: options.name ?? "absolutejs-voice-evals"
|
|
32881
33310
|
});
|
|
32882
33311
|
const getReport = () => runVoiceSessionEvals({
|
|
@@ -33013,11 +33442,11 @@ var createVoiceEvalRoutes = (options) => {
|
|
|
33013
33442
|
return routes;
|
|
33014
33443
|
};
|
|
33015
33444
|
// src/simulationSuite.ts
|
|
33016
|
-
import { Elysia as
|
|
33445
|
+
import { Elysia as Elysia52 } from "elysia";
|
|
33017
33446
|
|
|
33018
33447
|
// src/outcomeContract.ts
|
|
33019
|
-
import { Elysia as
|
|
33020
|
-
var
|
|
33448
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
33449
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
33021
33450
|
var resolveSessionHref4 = (value, sessionId) => {
|
|
33022
33451
|
if (value === false) {
|
|
33023
33452
|
return;
|
|
@@ -33228,13 +33657,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
33228
33657
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
33229
33658
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
33230
33659
|
const contracts = report.contracts.map((contract) => {
|
|
33231
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
33660
|
+
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${escapeHtml47(href)}">${escapeHtml47(contract.sessionIds[index] ?? href)}</a>`).join(" \xB7 ")}</p>` : "";
|
|
33232
33661
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
33233
33662
|
<div class="contract-header">
|
|
33234
33663
|
<div>
|
|
33235
|
-
<p class="eyebrow">${
|
|
33236
|
-
<h2>${
|
|
33237
|
-
${contract.description ? `<p>${
|
|
33664
|
+
<p class="eyebrow">${escapeHtml47(contract.contractId)}</p>
|
|
33665
|
+
<h2>${escapeHtml47(contract.label ?? contract.contractId)}</h2>
|
|
33666
|
+
${contract.description ? `<p>${escapeHtml47(contract.description)}</p>` : ""}
|
|
33238
33667
|
${sessionLinks}
|
|
33239
33668
|
</div>
|
|
33240
33669
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -33246,10 +33675,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
33246
33675
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
33247
33676
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
33248
33677
|
</div>
|
|
33249
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
33678
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml47(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
33250
33679
|
</section>`;
|
|
33251
33680
|
}).join("");
|
|
33252
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33681
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml47(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(14,165,233,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary,.grid{display:flex;flex-wrap:wrap;gap:10px}.pill,.grid span{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}li{margin:8px 0}@media(max-width:800px){main{padding:18px}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Business Outcome Verification</p><h1>${escapeHtml47(title)}</h1><div class="summary"><span class="pill ${report.status}">${report.status}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section>${contracts || '<section class="contract"><p>No outcome contracts configured.</p></section>'}</main></body></html>`;
|
|
33253
33682
|
};
|
|
33254
33683
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
33255
33684
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -33265,7 +33694,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
|
33265
33694
|
var createVoiceOutcomeContractRoutes = (options) => {
|
|
33266
33695
|
const path = options.path ?? "/api/outcome-contracts";
|
|
33267
33696
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
33268
|
-
const routes = new
|
|
33697
|
+
const routes = new Elysia50({
|
|
33269
33698
|
name: options.name ?? "absolutejs-voice-outcome-contracts"
|
|
33270
33699
|
}).get(path, createVoiceOutcomeContractJSONHandler(options));
|
|
33271
33700
|
if (htmlPath) {
|
|
@@ -33275,7 +33704,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
|
|
|
33275
33704
|
};
|
|
33276
33705
|
|
|
33277
33706
|
// src/toolContract.ts
|
|
33278
|
-
import { Elysia as
|
|
33707
|
+
import { Elysia as Elysia51 } from "elysia";
|
|
33279
33708
|
|
|
33280
33709
|
// src/toolRuntime.ts
|
|
33281
33710
|
var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -33484,7 +33913,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
33484
33913
|
});
|
|
33485
33914
|
var defaultApi = {};
|
|
33486
33915
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
33487
|
-
var
|
|
33916
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
33488
33917
|
var resolveSessionHref5 = (value, sessionId) => {
|
|
33489
33918
|
if (value === false) {
|
|
33490
33919
|
return;
|
|
@@ -33735,7 +34164,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
33735
34164
|
};
|
|
33736
34165
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
33737
34166
|
const title = options.title ?? "Voice Tool Contracts";
|
|
33738
|
-
const snippet =
|
|
34167
|
+
const snippet = escapeHtml48(`app.use(
|
|
33739
34168
|
createVoiceToolContractRoutes({
|
|
33740
34169
|
htmlPath: '/tool-contracts',
|
|
33741
34170
|
path: '/api/tool-contracts',
|
|
@@ -33761,20 +34190,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
33761
34190
|
);`);
|
|
33762
34191
|
const contracts = report.contracts.map((contract) => {
|
|
33763
34192
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
33764
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
34193
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml48(testCase.operationsRecordHref)}">${escapeHtml48(testCase.label ?? testCase.caseId)}</a>` : escapeHtml48(testCase.label ?? testCase.caseId)}</td>
|
|
33765
34194
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
33766
|
-
<td>${
|
|
33767
|
-
<td>${
|
|
34195
|
+
<td>${escapeHtml48(testCase.status)}</td>
|
|
34196
|
+
<td>${escapeHtml48(testCase.sessionId)}</td>
|
|
33768
34197
|
<td>${String(testCase.attempts)}</td>
|
|
33769
34198
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
33770
34199
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
33771
|
-
<td>${
|
|
34200
|
+
<td>${escapeHtml48(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
33772
34201
|
</tr>`).join("");
|
|
33773
34202
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
33774
34203
|
<div class="contract-header">
|
|
33775
34204
|
<div>
|
|
33776
|
-
<p class="eyebrow">${
|
|
33777
|
-
<h2>${
|
|
34205
|
+
<p class="eyebrow">${escapeHtml48(contract.toolName)}</p>
|
|
34206
|
+
<h2>${escapeHtml48(contract.label ?? contract.contractId)}</h2>
|
|
33778
34207
|
</div>
|
|
33779
34208
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
33780
34209
|
</div>
|
|
@@ -33784,7 +34213,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
33784
34213
|
</table>
|
|
33785
34214
|
</section>`;
|
|
33786
34215
|
}).join("");
|
|
33787
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
34216
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml48(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(245,158,11,.12))}.primitive{background:#151b20;border-color:#5a4421}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}h2{margin:.2rem 0 1rem}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}.primitive p{color:#d8dee6;line-height:1.55}.primitive pre{background:#0f1217;border:1px solid #2a323a;border-radius:16px;color:#fef3c7;overflow:auto;padding:14px}.primitive code{color:#fef3c7}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left;vertical-align:top}th{color:#a8b0b8;font-size:.82rem}@media(max-width:800px){main{padding:18px}table{display:block;overflow:auto}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Tool Reliability</p><h1>${escapeHtml48(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml48(report.status)}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceToolContractRoutes(...)</code> certifies tool behavior</h2><p>Define deterministic tool cases for retries, idempotency, timeouts, result shape, and error handling so assistant tools fail in pre-production instead of live calls.</p><pre><code>${snippet}</code></pre></section>${contracts || '<section class="contract"><p>No tool contracts configured.</p></section>'}</main></body></html>`;
|
|
33788
34217
|
};
|
|
33789
34218
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
33790
34219
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -33801,7 +34230,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
|
33801
34230
|
var createVoiceToolContractRoutes = (options) => {
|
|
33802
34231
|
const path = options.path ?? "/api/tool-contracts";
|
|
33803
34232
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
33804
|
-
const routes = new
|
|
34233
|
+
const routes = new Elysia51({
|
|
33805
34234
|
name: options.name ?? "absolutejs-voice-tool-contracts"
|
|
33806
34235
|
}).get(path, createVoiceToolContractJSONHandler(options));
|
|
33807
34236
|
if (htmlPath) {
|
|
@@ -33811,7 +34240,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
33811
34240
|
};
|
|
33812
34241
|
|
|
33813
34242
|
// src/simulationSuite.ts
|
|
33814
|
-
var
|
|
34243
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
33815
34244
|
var summarizeSection = (report) => ({
|
|
33816
34245
|
failed: report.failed,
|
|
33817
34246
|
passed: report.passed,
|
|
@@ -34007,15 +34436,15 @@ var renderSection = (label, summary) => {
|
|
|
34007
34436
|
if (!summary) {
|
|
34008
34437
|
return "";
|
|
34009
34438
|
}
|
|
34010
|
-
return `<article class="${
|
|
34439
|
+
return `<article class="${escapeHtml49(summary.status)}"><span>${escapeHtml49(label)}</span><strong>${escapeHtml49(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
|
|
34011
34440
|
};
|
|
34012
34441
|
var renderAction = (action) => {
|
|
34013
|
-
const content = `<strong>${
|
|
34014
|
-
return action.href ? `<a class="action" href="${
|
|
34442
|
+
const content = `<strong>${escapeHtml49(action.label)}</strong><p>${escapeHtml49(action.description)}</p><span>${escapeHtml49(action.section)} / ${escapeHtml49(action.severity)}</span>`;
|
|
34443
|
+
return action.href ? `<a class="action" href="${escapeHtml49(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
34015
34444
|
};
|
|
34016
34445
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
34017
34446
|
const title = options.title ?? "Voice Simulation Suite";
|
|
34018
|
-
const snippet =
|
|
34447
|
+
const snippet = escapeHtml49(`app.use(
|
|
34019
34448
|
createVoiceSimulationSuiteRoutes({
|
|
34020
34449
|
htmlPath: '/voice/simulations',
|
|
34021
34450
|
path: '/api/voice/simulations',
|
|
@@ -34048,12 +34477,12 @@ app.use(
|
|
|
34048
34477
|
store: traceStore
|
|
34049
34478
|
})
|
|
34050
34479
|
);`);
|
|
34051
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
34480
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml49(title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero,.primitive{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(59,130,246,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.primitive{background:#151d27;border-color:#355078}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid,.actions{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin:18px 0}.grid article,.action{background:#151d27;border:1px solid #283544;border-radius:18px;color:inherit;padding:16px;text-decoration:none}.grid span,.action span{color:#aab5c0}.grid strong{display:block;font-size:2rem;margin:.25rem 0;text-transform:uppercase}.action strong{display:block;color:#f8f3e7;margin-bottom:.35rem}.action p,.primitive p{color:#d8dee6;line-height:1.55;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}.primitive pre{background:#0b1118;color:#dbeafe}.primitive code{color:#bfdbfe}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml49(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml49(report.status)}">Status: ${escapeHtml49(report.status)}</p><section class="grid">${renderSection("Sessions", report.summary.sessions)}${renderSection("Scenarios", report.summary.scenarios)}${renderSection("Fixtures", report.summary.fixtures)}${renderSection("Tools", report.summary.tools)}${renderSection("Outcomes", report.summary.outcomes)}</section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceSimulationSuiteRoutes(...)</code> builds this pre-production proof surface</h2><p>Run session quality checks, scenario evals, fixture-backed simulations, tool contracts, and outcome contracts from one route group before live traffic sees a regression.</p><pre><code>${snippet}</code></pre></section><h2>Actions</h2><section class="actions">${report.actions.length > 0 ? report.actions.map(renderAction).join("") : '<article class="action"><strong>No action required</strong><p>All enabled simulation sections are passing.</p></article>'}</section><pre>${escapeHtml49(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
|
|
34052
34481
|
};
|
|
34053
34482
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
34054
34483
|
const path = options.path ?? "/api/voice/simulations";
|
|
34055
34484
|
const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
|
|
34056
|
-
const app = new
|
|
34485
|
+
const app = new Elysia52({
|
|
34057
34486
|
name: options.name ?? "absolutejs-voice-simulation-suite"
|
|
34058
34487
|
}).get(path, () => runVoiceSimulationSuite(options));
|
|
34059
34488
|
if (htmlPath) {
|
|
@@ -34680,10 +35109,10 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
34680
35109
|
return report;
|
|
34681
35110
|
};
|
|
34682
35111
|
// src/turnLatency.ts
|
|
34683
|
-
import { Elysia as
|
|
35112
|
+
import { Elysia as Elysia53 } from "elysia";
|
|
34684
35113
|
var DEFAULT_WARN_AFTER_MS2 = 1800;
|
|
34685
35114
|
var DEFAULT_FAIL_AFTER_MS2 = 3200;
|
|
34686
|
-
var
|
|
35115
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
34687
35116
|
var firstNumber4 = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
34688
35117
|
var getString19 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
34689
35118
|
var createTraceStageIndex = (events) => {
|
|
@@ -34798,7 +35227,7 @@ var summarizeVoiceTurnLatency = async (options) => {
|
|
|
34798
35227
|
warnings
|
|
34799
35228
|
};
|
|
34800
35229
|
};
|
|
34801
|
-
var
|
|
35230
|
+
var formatMs5 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
34802
35231
|
var renderVoiceTurnLatencyHTML = (report, options = {}) => {
|
|
34803
35232
|
const title = options.title ?? "Voice Turn Latency";
|
|
34804
35233
|
const snippet = `app.use(
|
|
@@ -34819,11 +35248,11 @@ await traceStore.append({
|
|
|
34819
35248
|
turnId,
|
|
34820
35249
|
type: 'turn_latency.stage'
|
|
34821
35250
|
});`;
|
|
34822
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
34823
|
-
<header><div><p class="eyebrow">${
|
|
34824
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
35251
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml50(turn.status)}">
|
|
35252
|
+
<header><div><p class="eyebrow">${escapeHtml50(turn.sessionId)} \xB7 ${escapeHtml50(turn.turnId)}</p><h2>${escapeHtml50(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml50(turn.status)}</strong></header>
|
|
35253
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml50(stage.label)}</dt><dd>${escapeHtml50(formatMs5(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
34825
35254
|
</article>`).join("");
|
|
34826
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
35255
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml50(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn,.primitive{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(251,191,36,.1))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.primitive p{color:#cbd5e1}.primitive pre{background:#0a0d10;border:1px solid #2a323a;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}.turn header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{font-weight:900;margin:0}@media(max-width:800px){main{padding:18px}.turn header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">End-to-end responsiveness</p><h1>${escapeHtml50(title)}</h1><div class="summary"><span class="pill ${escapeHtml50(report.status)}">${escapeHtml50(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml50(formatMs5(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTurnLatencyRoutes(...)</code> exposes the full turn waterfall</h2><p>Attach stage traces for speech detection, commit, model response, TTS send, and first audio so teams can prove where latency actually comes from.</p><pre><code>${escapeHtml50(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
34827
35256
|
};
|
|
34828
35257
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
34829
35258
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -34840,7 +35269,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
34840
35269
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
34841
35270
|
const path = options.path ?? "/api/turn-latency";
|
|
34842
35271
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
34843
|
-
const routes = new
|
|
35272
|
+
const routes = new Elysia53({
|
|
34844
35273
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
34845
35274
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
34846
35275
|
if (htmlPath) {
|
|
@@ -34849,8 +35278,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
34849
35278
|
return routes;
|
|
34850
35279
|
};
|
|
34851
35280
|
// src/liveLatency.ts
|
|
34852
|
-
import { Elysia as
|
|
34853
|
-
var
|
|
35281
|
+
import { Elysia as Elysia54 } from "elysia";
|
|
35282
|
+
var escapeHtml51 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
34854
35283
|
var percentile6 = (values, percentileValue) => {
|
|
34855
35284
|
if (values.length === 0) {
|
|
34856
35285
|
return;
|
|
@@ -34895,7 +35324,7 @@ var summarizeVoiceLiveLatency = async (options) => {
|
|
|
34895
35324
|
warnings
|
|
34896
35325
|
};
|
|
34897
35326
|
};
|
|
34898
|
-
var
|
|
35327
|
+
var formatMs6 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
34899
35328
|
var renderVoiceLiveLatencyHTML = (report, options = {}) => {
|
|
34900
35329
|
const title = options.title ?? "Voice Live Latency";
|
|
34901
35330
|
const snippet = `app.use(
|
|
@@ -34917,13 +35346,13 @@ await traceStore.append({
|
|
|
34917
35346
|
sessionId,
|
|
34918
35347
|
type: 'client.live_latency'
|
|
34919
35348
|
});`;
|
|
34920
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
34921
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
35349
|
+
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml51(sample.sessionId)}</td><td>${escapeHtml51(formatMs6(sample.latencyMs))}</td><td>${escapeHtml51(sample.status ?? "unknown")}</td><td>${escapeHtml51(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
35350
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml51(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(245,158,11,.1));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fbbf24}.fail{color:#fca5a5}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:18px 0}.metrics article,table,.primitive{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article,.primitive{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}.primitive{margin:0 0 18px}.primitive h2{margin:.2rem 0 .5rem}.primitive p{color:#cbd5e1}.primitive pre{background:#080b10;border:1px solid #26313d;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #26313d;padding:12px;text-align:left}@media(max-width:760px){main{padding:20px}}</style></head><body><main><section class="hero"><p class="eyebrow">Browser proof</p><h1>${escapeHtml51(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml51(report.status)}">Status: ${escapeHtml51(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml51(formatMs6(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml51(formatMs6(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml51(formatMs6(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceLiveLatencyRoutes(...)</code> turns real browser timing into a release gate</h2><p>Persist live timing samples into the trace store so readiness, simulations, and trace timelines all point at the same self-hosted proof.</p><pre><code>${escapeHtml51(snippet)}</code></pre></section><table><thead><tr><th>Session</th><th>Latency</th><th>Status</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="4">No live latency samples yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
34922
35351
|
};
|
|
34923
35352
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
34924
35353
|
const path = options.path ?? "/api/live-latency";
|
|
34925
35354
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
34926
|
-
const routes = new
|
|
35355
|
+
const routes = new Elysia54({
|
|
34927
35356
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
34928
35357
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
34929
35358
|
if (htmlPath) {
|
|
@@ -34940,9 +35369,9 @@ var createVoiceLiveLatencyRoutes = (options) => {
|
|
|
34940
35369
|
return routes;
|
|
34941
35370
|
};
|
|
34942
35371
|
// src/turnQuality.ts
|
|
34943
|
-
import { Elysia as
|
|
35372
|
+
import { Elysia as Elysia55 } from "elysia";
|
|
34944
35373
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
34945
|
-
var
|
|
35374
|
+
var escapeHtml52 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
34946
35375
|
var getTurnLatencyMs = (turn) => {
|
|
34947
35376
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
34948
35377
|
if (firstTranscriptAt === undefined) {
|
|
@@ -35012,24 +35441,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
35012
35441
|
};
|
|
35013
35442
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
35014
35443
|
const title = options.title ?? "Voice Turn Quality";
|
|
35015
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
35444
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml52(turn.status)}">
|
|
35016
35445
|
<div class="turn-header">
|
|
35017
35446
|
<div>
|
|
35018
|
-
<p class="eyebrow">${
|
|
35019
|
-
<h2>${
|
|
35447
|
+
<p class="eyebrow">${escapeHtml52(turn.sessionId)} \xB7 ${escapeHtml52(turn.turnId)}</p>
|
|
35448
|
+
<h2>${escapeHtml52(turn.text || "Empty turn")}</h2>
|
|
35020
35449
|
</div>
|
|
35021
|
-
<strong>${
|
|
35450
|
+
<strong>${escapeHtml52(turn.status)}</strong>
|
|
35022
35451
|
</div>
|
|
35023
35452
|
<dl>
|
|
35024
|
-
<div><dt>Source</dt><dd>${
|
|
35453
|
+
<div><dt>Source</dt><dd>${escapeHtml52(turn.source ?? "unknown")}</dd></div>
|
|
35025
35454
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
35026
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
35027
|
-
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${
|
|
35455
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml52(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
35456
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml52(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
35028
35457
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
35029
35458
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
35030
35459
|
</dl>
|
|
35031
35460
|
</article>`).join("");
|
|
35032
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
35461
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml52(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(251,191,36,.16),rgba(34,197,94,.1))}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.turn-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.unknown{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.turn-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime STT Debugging</p><h1>${escapeHtml52(title)}</h1><div class="summary"><span class="pill ${escapeHtml52(report.status)}">${escapeHtml52(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span><span class="pill">${String(report.sessions)} sessions</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
35033
35462
|
};
|
|
35034
35463
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
35035
35464
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -35046,7 +35475,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
35046
35475
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
35047
35476
|
const path = options.path ?? "/api/turn-quality";
|
|
35048
35477
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
35049
|
-
const routes = new
|
|
35478
|
+
const routes = new Elysia55({
|
|
35050
35479
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
35051
35480
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
35052
35481
|
if (htmlPath) {
|
|
@@ -35055,10 +35484,10 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
35055
35484
|
return routes;
|
|
35056
35485
|
};
|
|
35057
35486
|
// src/phoneAgent.ts
|
|
35058
|
-
import { Elysia as
|
|
35487
|
+
import { Elysia as Elysia57 } from "elysia";
|
|
35059
35488
|
|
|
35060
35489
|
// src/phoneAgentProductionSmoke.ts
|
|
35061
|
-
import { Elysia as
|
|
35490
|
+
import { Elysia as Elysia56 } from "elysia";
|
|
35062
35491
|
var defaultRequirements = [
|
|
35063
35492
|
"media-started",
|
|
35064
35493
|
"transcript",
|
|
@@ -35066,7 +35495,7 @@ var defaultRequirements = [
|
|
|
35066
35495
|
"lifecycle-outcome",
|
|
35067
35496
|
"no-session-error"
|
|
35068
35497
|
];
|
|
35069
|
-
var
|
|
35498
|
+
var escapeHtml53 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
35070
35499
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
35071
35500
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
35072
35501
|
const value = event.payload[key];
|
|
@@ -35175,10 +35604,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
35175
35604
|
});
|
|
35176
35605
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
35177
35606
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
35178
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
35179
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
35180
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
35181
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
35607
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml53(issue.requirement)}</strong>: ${escapeHtml53(issue.message)}</li>`).join("");
|
|
35608
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml53(outcome)}</span>`).join("");
|
|
35609
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml53(requirement)}</span>`).join("");
|
|
35610
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml53(title)}</title><style>body{background:#0e141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1050px;padding:32px}.hero,.panel{background:#151d26;border:1px solid #283544;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:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.metric{background:#0f151d;border:1px solid #283544;border-radius:16px;padding:14px}.metric strong{display:block;font-size:1.8rem}.pill{background:#0f151d;border:1px solid #3f3f46;border-radius:999px;display:inline-flex;margin:4px;padding:7px 10px}.issues{color:#fca5a5}code{color:#fde68a}@media(max-width:720px){main{padding:18px}}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent production smoke</p><h1>${escapeHtml53(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml53(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml53(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml53(report.sessionId)}</code>` : ""}.</p></section><section class="panel"><h2>Observed Trace Evidence</h2><div class="grid"><div class="metric"><span>Media starts</span><strong>${String(report.observed.mediaStarts)}</strong></div><div class="metric"><span>Transcripts</span><strong>${String(report.observed.transcripts)}</strong></div><div class="metric"><span>Assistant responses</span><strong>${String(report.observed.assistantResponses)}</strong></div><div class="metric"><span>Session errors</span><strong>${String(report.observed.sessionErrors)}</strong></div></div><p>${outcomes || '<span class="pill">No lifecycle outcome</span>'}</p></section><section class="panel"><h2>Requirements</h2><p>${requirements}</p>${issues ? `<ul class="issues">${issues}</ul>` : '<p class="pass">All required phone-agent smoke evidence is present.</p>'}</section></main></body></html>`;
|
|
35182
35611
|
};
|
|
35183
35612
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
35184
35613
|
query,
|
|
@@ -35201,7 +35630,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
35201
35630
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
35202
35631
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
35203
35632
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
35204
|
-
const routes = new
|
|
35633
|
+
const routes = new Elysia56({
|
|
35205
35634
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
35206
35635
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
35207
35636
|
if (htmlPath) {
|
|
@@ -35244,7 +35673,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
35244
35673
|
"completed",
|
|
35245
35674
|
"failed"
|
|
35246
35675
|
];
|
|
35247
|
-
var
|
|
35676
|
+
var escapeHtml54 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
35248
35677
|
var loadRouteJson = async (input) => {
|
|
35249
35678
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
35250
35679
|
headers: {
|
|
@@ -35482,10 +35911,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
35482
35911
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
35483
35912
|
const urls = entry?.setup.urls;
|
|
35484
35913
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
35485
|
-
return `<tr><td>${
|
|
35914
|
+
return `<tr><td>${escapeHtml54(carrier.name ?? carrier.provider)}</td><td>${escapeHtml54(carrier.provider)}</td><td><code>${escapeHtml54(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml54(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml54(entry.status)}">${escapeHtml54(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml54(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml54(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml54(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
|
|
35486
35915
|
}).join("");
|
|
35487
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
35488
|
-
const snippet =
|
|
35916
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml54(stage)}</code></li>`).join("");
|
|
35917
|
+
const snippet = escapeHtml54(`const phoneAgent = createVoicePhoneAgent({
|
|
35489
35918
|
carriers: [
|
|
35490
35919
|
{
|
|
35491
35920
|
provider: 'twilio',
|
|
@@ -35519,11 +35948,11 @@ app.use(
|
|
|
35519
35948
|
);`);
|
|
35520
35949
|
const checklist = report.carriers.map((carrier) => {
|
|
35521
35950
|
const instruction = report.setupInstructions.find((candidate) => candidate.provider === carrier.provider && candidate.carrierName === (carrier.name ?? carrier.provider));
|
|
35522
|
-
const issueList = instruction?.issues.map((issue) => `<li>${
|
|
35523
|
-
const steps = instruction?.steps.map((step) => `<li>${
|
|
35524
|
-
return `<article><h3>${
|
|
35951
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml54(issue)}</li>`).join("") ?? "";
|
|
35952
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml54(step)}</li>`).join("") ?? "";
|
|
35953
|
+
return `<article><h3>${escapeHtml54(carrier.name ?? carrier.provider)}</h3><ol>${steps}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
|
|
35525
35954
|
}).join("");
|
|
35526
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
35955
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml54(report.title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.primitive{background:#151d27;border-color:#365a60}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.warn{color:#fde68a}.muted{color:#aab5c0}table{background:#151d27;border:1px solid #283544;border-collapse:collapse;border-radius:18px;display:block;overflow:auto;width:100%}td,th{border-bottom:1px solid #283544;padding:12px;text-align:left;vertical-align:top}code{color:#fde68a;overflow-wrap:anywhere}.primitive p{color:#cbd5de;line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #283544;border-radius:18px;color:#fef3c7;overflow:auto;padding:16px}.checklist{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));margin:18px 0}.checklist article{background:#151d27;border:1px solid #283544;border-radius:18px;padding:18px}.checklist ol{padding-left:20px}.issues{color:#fca5a5}.stages{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));padding-left:18px}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent setup</p><h1>${escapeHtml54(report.title)}</h1><p>One self-hosted entrypoint for carrier routes, setup reports, smoke checks, and normalized call lifecycle stages.</p><p class="badge ${report.ready ? "pass" : "fail"}">Ready: ${String(report.ready)}</p>${report.matrixPath ? `<p><a href="${escapeHtml54(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoicePhoneAgent(...)</code> builds this carrier control plane</h2><p>Mount carrier routes once, expose setup and smoke proof, then feed the same carrier matrix and phone-agent smoke reports into production readiness so carrier regressions block deploys.</p><pre><code>${snippet}</code></pre></section><h2>Carrier Setup Checklist</h2><section class="checklist">${checklist}</section><h2>Carrier URLs</h2><table><thead><tr><th>Name</th><th>Provider</th><th>Setup</th><th>Smoke</th><th>Status</th><th>Answer/TwiML/TeXML</th><th>Webhook</th><th>Stream</th></tr></thead><tbody>${carrierRows}</tbody></table><h2>Lifecycle Schema</h2><ul class="stages">${stageList}</ul></main></body></html>`;
|
|
35527
35956
|
};
|
|
35528
35957
|
var createVoicePhoneAgent = (options) => {
|
|
35529
35958
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -35532,7 +35961,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
35532
35961
|
setupPath: resolveSetupPath(carrier),
|
|
35533
35962
|
smokePath: resolveSmokePath(carrier)
|
|
35534
35963
|
}));
|
|
35535
|
-
const app = new
|
|
35964
|
+
const app = new Elysia57({
|
|
35536
35965
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
35537
35966
|
});
|
|
35538
35967
|
for (const carrier of options.carriers) {
|
|
@@ -37281,8 +37710,8 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
37281
37710
|
};
|
|
37282
37711
|
};
|
|
37283
37712
|
// src/providerCapabilities.ts
|
|
37284
|
-
import { Elysia as
|
|
37285
|
-
var
|
|
37713
|
+
import { Elysia as Elysia58 } from "elysia";
|
|
37714
|
+
var escapeHtml55 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
37286
37715
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
37287
37716
|
configured: true,
|
|
37288
37717
|
features: options.features?.[provider],
|
|
@@ -37347,27 +37776,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
37347
37776
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
37348
37777
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
37349
37778
|
const cards = report.capabilities.map((capability) => {
|
|
37350
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
37351
|
-
return `<article class="card ${
|
|
37779
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml55(feature)}</span>`).join("");
|
|
37780
|
+
return `<article class="card ${escapeHtml55(capability.status)}">
|
|
37352
37781
|
<div class="card-header">
|
|
37353
37782
|
<div>
|
|
37354
|
-
<p class="eyebrow">${
|
|
37355
|
-
<h2>${
|
|
37783
|
+
<p class="eyebrow">${escapeHtml55(capability.kind)}</p>
|
|
37784
|
+
<h2>${escapeHtml55(capability.label ?? capability.provider)}</h2>
|
|
37356
37785
|
</div>
|
|
37357
|
-
<strong>${
|
|
37786
|
+
<strong>${escapeHtml55(capability.status)}</strong>
|
|
37358
37787
|
</div>
|
|
37359
|
-
${capability.description ? `<p>${
|
|
37788
|
+
${capability.description ? `<p>${escapeHtml55(capability.description)}</p>` : ""}
|
|
37360
37789
|
<dl>
|
|
37361
37790
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
37362
37791
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
37363
|
-
<div><dt>Model</dt><dd>${
|
|
37792
|
+
<div><dt>Model</dt><dd>${escapeHtml55(capability.model ?? "default")}</dd></div>
|
|
37364
37793
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
37365
37794
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
37366
37795
|
</dl>
|
|
37367
37796
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
37368
37797
|
</article>`;
|
|
37369
37798
|
}).join("");
|
|
37370
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
37799
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml55(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.16),rgba(34,197,94,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary,.features{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.selected,.healthy{color:#86efac}.unconfigured,.degraded,.rate-limited,.suppressed{color:#fca5a5}.idle,.recoverable{color:#fde68a}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Discovery</p><h1>${escapeHtml55(title)}</h1><div class="summary"><span class="pill">${String(report.configured)} configured</span><span class="pill">${String(report.selected)} selected</span><span class="pill">${String(report.unconfigured)} missing</span><span class="pill">${String(report.total)} total</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider capabilities configured.</p></article>'}</section></main></body></html>`;
|
|
37371
37800
|
};
|
|
37372
37801
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
37373
37802
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -37384,7 +37813,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
37384
37813
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
37385
37814
|
const path = options.path ?? "/api/provider-capabilities";
|
|
37386
37815
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
37387
|
-
const routes = new
|
|
37816
|
+
const routes = new Elysia58({
|
|
37388
37817
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
37389
37818
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
37390
37819
|
if (htmlPath) {
|
|
@@ -37393,7 +37822,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
37393
37822
|
return routes;
|
|
37394
37823
|
};
|
|
37395
37824
|
// src/providerOrchestration.ts
|
|
37396
|
-
import { Elysia as
|
|
37825
|
+
import { Elysia as Elysia59 } from "elysia";
|
|
37397
37826
|
var defaultRequirement = {
|
|
37398
37827
|
minProviders: 1,
|
|
37399
37828
|
requireBudgetPolicy: false,
|
|
@@ -37406,7 +37835,7 @@ var statusRank7 = {
|
|
|
37406
37835
|
warn: 1,
|
|
37407
37836
|
fail: 2
|
|
37408
37837
|
};
|
|
37409
|
-
var
|
|
37838
|
+
var escapeHtml56 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
37410
37839
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
37411
37840
|
var uniqueSorted8 = (values) => [
|
|
37412
37841
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -37549,27 +37978,27 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
37549
37978
|
};
|
|
37550
37979
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
37551
37980
|
const title = options.title ?? "Voice Provider Orchestration";
|
|
37552
|
-
const cards = report.surfaces.map((surface) => `<article class="card ${
|
|
37553
|
-
<div class="card-header"><div><p class="eyebrow">${
|
|
37981
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml56(surface.status)}">
|
|
37982
|
+
<div class="card-header"><div><p class="eyebrow">${escapeHtml56(surface.surface)}</p><h2>${escapeHtml56(surface.strategy ?? "default policy")}</h2></div><strong>${escapeHtml56(surface.status)}</strong></div>
|
|
37554
37983
|
<dl>
|
|
37555
|
-
<div><dt>Providers</dt><dd>${
|
|
37556
|
-
<div><dt>Fallback</dt><dd>${
|
|
37984
|
+
<div><dt>Providers</dt><dd>${escapeHtml56(surface.providers.join(", ") || "none")}</dd></div>
|
|
37985
|
+
<div><dt>Fallback</dt><dd>${escapeHtml56(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
37557
37986
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
37558
37987
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
37559
37988
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
37560
37989
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
37561
37990
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
37562
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
37991
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml56(surface.fallbackMode || "default")}</dd></div>
|
|
37563
37992
|
</dl>
|
|
37564
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
37993
|
+
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${escapeHtml56(issue.status)}</strong> ${escapeHtml56(issue.message)}</li>`).join("")}</ul>` : "<p>No orchestration issues.</p>"}
|
|
37565
37994
|
</article>`).join("");
|
|
37566
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
37995
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml56(title)}</title><style>body{background:#111827;color:#f9fafb;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#172033;border:1px solid #2d3b55;border-radius:22px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(59,130,246,.18),rgba(20,184,166,.12))}.eyebrow{color:#93c5fd;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f172a;border:1px solid #334155;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass strong{color:#86efac}.warn strong{color:#fde68a}.fail strong{color:#fca5a5}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0;overflow-wrap:anywhere}li{margin:.35rem 0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Policy Proof</p><h1>${escapeHtml56(title)}</h1><div class="summary"><span class="pill">${escapeHtml56(report.profileId)}</span><span class="pill">${escapeHtml56(report.status)}</span><span class="pill">${String(report.summary.surfaces)} surfaces</span><span class="pill">${String(report.summary.providers)} providers</span><span class="pill">${String(report.issues.length)} issues</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider orchestration surfaces configured.</p></article>'}</section></main></body></html>`;
|
|
37567
37996
|
};
|
|
37568
37997
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
37569
37998
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
37570
37999
|
const htmlPath = options.htmlPath === undefined ? "/voice/provider-orchestration" : options.htmlPath;
|
|
37571
38000
|
const markdownPath = options.markdownPath === undefined ? "/voice/provider-orchestration.md" : options.markdownPath;
|
|
37572
|
-
const routes = new
|
|
38001
|
+
const routes = new Elysia59({
|
|
37573
38002
|
name: options.name ?? "absolutejs-voice-provider-orchestration"
|
|
37574
38003
|
}).get(path, () => buildVoiceProviderOrchestrationReport(options));
|
|
37575
38004
|
if (htmlPath) {
|
|
@@ -37742,8 +38171,8 @@ var assertVoiceProviderRoutingContractEvidence = (reports, input = {}) => {
|
|
|
37742
38171
|
return report;
|
|
37743
38172
|
};
|
|
37744
38173
|
// src/voiceMonitoring.ts
|
|
37745
|
-
import { Elysia as
|
|
37746
|
-
var
|
|
38174
|
+
import { Elysia as Elysia60 } from "elysia";
|
|
38175
|
+
var escapeHtml57 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
37747
38176
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
37748
38177
|
var rollupStatus5 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
37749
38178
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
@@ -37996,14 +38425,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
37996
38425
|
};
|
|
37997
38426
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
37998
38427
|
const title = options.title ?? "Voice Monitors";
|
|
37999
|
-
const runs = report.runs.map((run) => `<tr><td>${
|
|
38000
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
38001
|
-
const snippet =
|
|
38428
|
+
const runs = report.runs.map((run) => `<tr><td>${escapeHtml57(run.label)}</td><td class="${escapeHtml57(run.status)}">${escapeHtml57(run.status)}</td><td>${escapeHtml57(run.severity)}</td><td>${escapeHtml57(String(run.value ?? ""))}</td><td>${escapeHtml57(String(run.threshold ?? ""))}</td><td>${escapeHtml57(run.detail ?? "")}</td></tr>`).join("");
|
|
38429
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml57(issue.label)}</strong> <span class="${escapeHtml57(issue.status)}">${escapeHtml57(issue.status)}</span> ${escapeHtml57(issue.detail ?? "")}</li>`).join("");
|
|
38430
|
+
const snippet = escapeHtml57(`app.use(createVoiceMonitorRoutes({
|
|
38002
38431
|
evidence,
|
|
38003
38432
|
issueStore,
|
|
38004
38433
|
monitors: [defineVoiceMonitor(...)]
|
|
38005
38434
|
}));`);
|
|
38006
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
38435
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml57(title)}</title><style>body{background:#10141b;color:#f8f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero,.card{background:#171f2b;border:1px solid #2e3a4b;border-radius:24px;margin-bottom:16px;padding:22px}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);line-height:.92;margin:.2rem 0 1rem}.pill{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;margin-right:8px;padding:8px 12px}.pass{color:#86efac}.warn,.acknowledged{color:#fde68a}.fail,.open{color:#fca5a5}.resolved,.muted{color:#cbd5e1}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3a4b;padding:12px;text-align:left;vertical-align:top}pre{background:#0c1118;border:1px solid #2e3a4b;border-radius:16px;color:#dbeafe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Code-owned monitoring</p><h1>${escapeHtml57(title)}</h1><p class="pill ${escapeHtml57(report.status)}">Status: ${escapeHtml57(report.status)}</p><p class="pill">Open issues: ${String(report.summary.open)}</p><p class="pill">Critical: ${String(report.summary.criticalOpen)}</p></section><section class="card"><h2>Monitor Runs</h2><table><thead><tr><th>Monitor</th><th>Status</th><th>Severity</th><th>Value</th><th>Threshold</th><th>Detail</th></tr></thead><tbody>${runs}</tbody></table></section><section class="card"><h2>Issues</h2>${issues ? `<ul>${issues}</ul>` : '<p class="pass">No monitor issues.</p>'}</section><section class="card"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceMonitorRoutes(...)</code></h2><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
38007
38436
|
};
|
|
38008
38437
|
var actorFromRequest = async (request) => {
|
|
38009
38438
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -38027,7 +38456,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
38027
38456
|
monitors: options.monitors,
|
|
38028
38457
|
now: options.now
|
|
38029
38458
|
});
|
|
38030
|
-
const routes = new
|
|
38459
|
+
const routes = new Elysia60({
|
|
38031
38460
|
name: options.name ?? "absolutejs-voice-monitoring"
|
|
38032
38461
|
}).get(path, report).get(`${path}.md`, async () => {
|
|
38033
38462
|
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
@@ -38074,7 +38503,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
38074
38503
|
};
|
|
38075
38504
|
var createVoiceMonitorRunnerRoutes = (options) => {
|
|
38076
38505
|
const path = options.path ?? "/api/voice/monitor-runner";
|
|
38077
|
-
return new
|
|
38506
|
+
return new Elysia60({
|
|
38078
38507
|
name: options.name ?? "absolutejs-voice-monitor-runner"
|
|
38079
38508
|
}).get(path, () => ({
|
|
38080
38509
|
isRunning: options.runner.isRunning()
|
|
@@ -38462,8 +38891,8 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
38462
38891
|
};
|
|
38463
38892
|
};
|
|
38464
38893
|
// src/providerStackRecommendations.ts
|
|
38465
|
-
import { Elysia as
|
|
38466
|
-
var
|
|
38894
|
+
import { Elysia as Elysia61 } from "elysia";
|
|
38895
|
+
var escapeHtml58 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
38467
38896
|
var profileProviderPriorities = {
|
|
38468
38897
|
"meeting-recorder": {
|
|
38469
38898
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -38778,17 +39207,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
38778
39207
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
38779
39208
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
38780
39209
|
const rows = report.rows.map((row) => {
|
|
38781
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
38782
|
-
return `<article class="row ${
|
|
39210
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml58(check.status)}"><strong>${escapeHtml58(check.label)}</strong><span>${escapeHtml58(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml58(check.remediation.href)}">${escapeHtml58(check.remediation.label)}</a>` : escapeHtml58(check.remediation.label)}: ${escapeHtml58(check.remediation.detail)}</em>` : ""}</li>`).join("");
|
|
39211
|
+
return `<article class="row ${escapeHtml58(row.status)}">
|
|
38783
39212
|
<div>
|
|
38784
|
-
<p class="eyebrow">${
|
|
38785
|
-
<h2>${
|
|
38786
|
-
<p class="status ${
|
|
39213
|
+
<p class="eyebrow">${escapeHtml58(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
39214
|
+
<h2>${escapeHtml58(row.provider)}</h2>
|
|
39215
|
+
<p class="status ${escapeHtml58(row.status)}">${escapeHtml58(row.status.toUpperCase())}</p>
|
|
38787
39216
|
</div>
|
|
38788
39217
|
<ul>${checks}</ul>
|
|
38789
39218
|
</article>`;
|
|
38790
39219
|
}).join("");
|
|
38791
|
-
const snippet =
|
|
39220
|
+
const snippet = escapeHtml58(`const providerContracts = () =>
|
|
38792
39221
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
38793
39222
|
env: process.env,
|
|
38794
39223
|
providers: {
|
|
@@ -38809,7 +39238,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
38809
39238
|
providerContractMatrix: () =>
|
|
38810
39239
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
38811
39240
|
});`);
|
|
38812
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
39241
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml58(title)}</title><style>body{background:#0f1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.row{background:#17201b;border:1px solid #2d3b32;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(125,211,252,.12))}.primitive{background:#111814;border-color:#41604a}.eyebrow{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.primitive code{color:#bbf7d0}.primitive p{color:#c8d8ca;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#08110d;border:1px solid #294132;border-radius:18px;color:#d9f99d;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.row.pass,.pass{border-color:rgba(34,197,94,.65)}.status.warn,.row.warn,.warn{border-color:rgba(245,158,11,.7)}.status.fail,.row.fail,.fail{border-color:rgba(239,68,68,.75)}.row{display:grid;gap:20px;grid-template-columns:minmax(180px,.45fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#111814;border:1px solid #2d3b32;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}.row li em{color:#f9d77e;font-style:normal}.row li a{color:#86efac}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider contracts</p><h1>${escapeHtml58(title)}</h1><p>Self-hosted provider proof for configured state, required env, latency budgets, fallback, streaming, and declared capabilities.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderContractMatrixPreset(...)</code> builds this matrix</h2><p>Give AbsoluteJS your configured LLM, STT, and TTS providers once. It turns them into deploy-checkable proof for env, fallback, streaming, latency budgets, selected providers, and profile-required capabilities without a hosted dashboard.</p><pre><code>${snippet}</code></pre></section>${rows || '<article class="row"><p>No provider contracts configured.</p></article>'}</main></body></html>`;
|
|
38813
39242
|
};
|
|
38814
39243
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
38815
39244
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -38824,7 +39253,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
38824
39253
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
38825
39254
|
const path = options.path ?? "/api/provider-contracts";
|
|
38826
39255
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
38827
|
-
const routes = new
|
|
39256
|
+
const routes = new Elysia61({
|
|
38828
39257
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
38829
39258
|
});
|
|
38830
39259
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -38942,7 +39371,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
38942
39371
|
return assertion;
|
|
38943
39372
|
};
|
|
38944
39373
|
// src/opsConsoleRoutes.ts
|
|
38945
|
-
import { Elysia as
|
|
39374
|
+
import { Elysia as Elysia62 } from "elysia";
|
|
38946
39375
|
var DEFAULT_LINKS = [
|
|
38947
39376
|
{
|
|
38948
39377
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -38977,7 +39406,7 @@ var DEFAULT_LINKS = [
|
|
|
38977
39406
|
label: "Handoffs"
|
|
38978
39407
|
}
|
|
38979
39408
|
];
|
|
38980
|
-
var
|
|
39409
|
+
var escapeHtml59 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
38981
39410
|
var countProviderStatuses = (providers) => {
|
|
38982
39411
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
38983
39412
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -39046,20 +39475,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
39046
39475
|
trace
|
|
39047
39476
|
};
|
|
39048
39477
|
};
|
|
39049
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
39478
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml59(input.label)}</span><strong>${escapeHtml59(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml59(input.status)}">${escapeHtml59(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml59(input.href)}">Open</a>` : ""}</article>`;
|
|
39050
39479
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
39051
39480
|
const links = report.links.map((link) => `<article class="surface">
|
|
39052
|
-
<div><h2>${
|
|
39053
|
-
<p><a href="${
|
|
39481
|
+
<div><h2>${escapeHtml59(link.label)}</h2>${link.description ? `<p>${escapeHtml59(link.description)}</p>` : ""}</div>
|
|
39482
|
+
<p><a href="${escapeHtml59(link.href)}">Open ${escapeHtml59(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml59(link.statusHref)}">Status</a>` : ""}</p>
|
|
39054
39483
|
</article>`).join("");
|
|
39055
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
39056
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
39484
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml59(session.sessionId)}</td><td>${escapeHtml59(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml59(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
39485
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml59(event.kind)}</td><td>${escapeHtml59(event.provider ?? "unknown")}</td><td>${escapeHtml59(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml59(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
39057
39486
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
39058
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
39487
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml59(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#101316;color:#f6f2e8;margin:0}main{max-width:1180px;margin:auto;padding:32px}a{color:#fbbf24}header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;margin-bottom:24px}.eyebrow{color:#fbbf24;font-weight:800;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.5rem);line-height:.95;margin:.2rem 0 1rem}.muted{color:#a8b0b8}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.metric,.surface{background:#181d22;border:1px solid #2a323a;border-radius:20px;padding:18px}.metric strong{display:block;font-size:2.2rem;margin:.25rem 0}.pass,.healthy{color:#86efac}.fail,.failed,.degraded{color:#fca5a5}.surfaces{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:24px 0}table{width:100%;border-collapse:collapse;background:#181d22;border-radius:16px;overflow:hidden;margin:12px 0 28px}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left}section{margin-top:30px}@media(max-width:700px){main{padding:20px}header{display:block}}</style></head><body><main><header><div><p class="eyebrow">Self-hosted voice operations</p><h1>${escapeHtml59(title)}</h1><p class="muted">One deployable control plane for quality gates, failover, traces, sessions, handoffs, and provider health.</p></div><p class="muted">Checked ${escapeHtml59(new Date(report.checkedAt).toLocaleString())}</p></header><div class="grid">${renderMetricCard({ label: "Quality", value: report.quality.status, status: report.quality.status, href: "/quality" })}${renderMetricCard({ label: "Events", value: report.eventCount, href: "/diagnostics" })}${renderMetricCard({ label: "Sessions", value: report.sessions.total, status: report.sessions.failed > 0 ? "failed" : "healthy", href: "/sessions" })}${renderMetricCard({ label: "Handoffs failed", value: report.handoffs.failed, status: report.handoffs.failed > 0 ? "failed" : "healthy", href: "/handoffs" })}${renderMetricCard({ label: "Providers degraded", value: report.providers.degraded, status: report.providers.degraded > 0 ? "degraded" : "healthy", href: "/resilience" })}</div><section><h2>Operational Surfaces</h2><div class="surfaces">${links}</div></section><section><h2>Recent Sessions</h2><table><thead><tr><th>Session</th><th>Status</th><th>Turns</th><th>Errors</th><th>Replay</th></tr></thead><tbody>${sessions}</tbody></table></section><section><h2>Recent Provider Routing</h2><table><thead><tr><th>Kind</th><th>Provider</th><th>Status</th><th>Elapsed</th><th>Session</th></tr></thead><tbody>${routing}</tbody></table></section></main></body></html>`;
|
|
39059
39488
|
};
|
|
39060
39489
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
39061
39490
|
const path = options.path ?? "/ops-console";
|
|
39062
|
-
const routes = new
|
|
39491
|
+
const routes = new Elysia62({
|
|
39063
39492
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
39064
39493
|
});
|
|
39065
39494
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -39075,246 +39504,6 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
39075
39504
|
routes.get(`${path}/json`, async () => getReport());
|
|
39076
39505
|
return routes;
|
|
39077
39506
|
};
|
|
39078
|
-
// src/sessionObservability.ts
|
|
39079
|
-
import { Elysia as Elysia62 } from "elysia";
|
|
39080
|
-
var escapeHtml59 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
39081
|
-
var formatMs6 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
39082
|
-
var resolveHref = (href, sessionId) => {
|
|
39083
|
-
if (href === false) {
|
|
39084
|
-
return;
|
|
39085
|
-
}
|
|
39086
|
-
if (typeof href === "function") {
|
|
39087
|
-
return href(sessionId);
|
|
39088
|
-
}
|
|
39089
|
-
if (typeof href === "string") {
|
|
39090
|
-
return href.includes(":sessionId") ? href.replaceAll(":sessionId", encodeURIComponent(sessionId)) : `${href.replace(/\/$/, "")}/${encodeURIComponent(sessionId)}`;
|
|
39091
|
-
}
|
|
39092
|
-
return;
|
|
39093
|
-
};
|
|
39094
|
-
var buildLinks = (options) => {
|
|
39095
|
-
const links = [];
|
|
39096
|
-
const add = (rel, label, href) => {
|
|
39097
|
-
if (href) {
|
|
39098
|
-
links.push({ href, label, rel });
|
|
39099
|
-
}
|
|
39100
|
-
};
|
|
39101
|
-
add("operations-record", "Open operations record", resolveHref(options.operationsRecordHref, options.sessionId));
|
|
39102
|
-
add("trace-timeline", "Open trace timeline", resolveHref(options.traceTimelineHref, options.sessionId));
|
|
39103
|
-
add("call-debugger", "Open call debugger", resolveHref(options.callDebuggerHref, options.sessionId));
|
|
39104
|
-
add("incident-markdown", "Download incident Markdown", resolveHref(options.incidentMarkdownHref, options.sessionId));
|
|
39105
|
-
return [...links, ...options.customLinks ?? []];
|
|
39106
|
-
};
|
|
39107
|
-
var buildTurnWaterfalls = (record) => {
|
|
39108
|
-
const byTurn = new Map;
|
|
39109
|
-
const getTurn = (turnId) => {
|
|
39110
|
-
const existing = byTurn.get(turnId);
|
|
39111
|
-
if (existing) {
|
|
39112
|
-
return existing;
|
|
39113
|
-
}
|
|
39114
|
-
const turn = {
|
|
39115
|
-
assistantReplies: 0,
|
|
39116
|
-
errors: 0,
|
|
39117
|
-
providerDecisions: 0,
|
|
39118
|
-
stages: [],
|
|
39119
|
-
toolCalls: 0,
|
|
39120
|
-
transcripts: 0
|
|
39121
|
-
};
|
|
39122
|
-
byTurn.set(turnId, turn);
|
|
39123
|
-
return turn;
|
|
39124
|
-
};
|
|
39125
|
-
for (const event of record.timeline) {
|
|
39126
|
-
if (!event.turnId) {
|
|
39127
|
-
continue;
|
|
39128
|
-
}
|
|
39129
|
-
const turn = getTurn(event.turnId);
|
|
39130
|
-
turn.stages.push({
|
|
39131
|
-
at: event.at,
|
|
39132
|
-
elapsedMs: event.elapsedMs,
|
|
39133
|
-
label: event.label,
|
|
39134
|
-
offsetMs: event.offsetMs,
|
|
39135
|
-
provider: event.provider,
|
|
39136
|
-
status: event.status,
|
|
39137
|
-
type: event.type
|
|
39138
|
-
});
|
|
39139
|
-
if (event.type === "turn.transcript") {
|
|
39140
|
-
turn.transcripts += 1;
|
|
39141
|
-
}
|
|
39142
|
-
if (event.type === "turn.assistant") {
|
|
39143
|
-
turn.assistantReplies += 1;
|
|
39144
|
-
}
|
|
39145
|
-
if (event.type === "agent.tool") {
|
|
39146
|
-
turn.toolCalls += 1;
|
|
39147
|
-
}
|
|
39148
|
-
if (event.type === "provider.decision") {
|
|
39149
|
-
turn.providerDecisions += 1;
|
|
39150
|
-
}
|
|
39151
|
-
if (event.type === "session.error" || event.status === "error") {
|
|
39152
|
-
turn.errors += 1;
|
|
39153
|
-
}
|
|
39154
|
-
}
|
|
39155
|
-
for (const transcript of record.transcript) {
|
|
39156
|
-
const turn = getTurn(transcript.id);
|
|
39157
|
-
turn.assistantReplies = Math.max(turn.assistantReplies, transcript.assistantReplies.length);
|
|
39158
|
-
turn.errors += transcript.errors.length;
|
|
39159
|
-
turn.transcripts = Math.max(turn.transcripts, transcript.transcripts.length);
|
|
39160
|
-
}
|
|
39161
|
-
return [...byTurn.entries()].map(([turnId, turn]) => {
|
|
39162
|
-
const startedAt = turn.stages[0]?.at;
|
|
39163
|
-
const endedAt = turn.stages.at(-1)?.at;
|
|
39164
|
-
return {
|
|
39165
|
-
assistantReplies: turn.assistantReplies,
|
|
39166
|
-
durationMs: startedAt !== undefined && endedAt !== undefined ? Math.max(0, endedAt - startedAt) : undefined,
|
|
39167
|
-
endedAt,
|
|
39168
|
-
errors: turn.errors,
|
|
39169
|
-
providerDecisions: turn.providerDecisions,
|
|
39170
|
-
stages: turn.stages,
|
|
39171
|
-
startedAt,
|
|
39172
|
-
toolCalls: turn.toolCalls,
|
|
39173
|
-
transcripts: turn.transcripts,
|
|
39174
|
-
turnId
|
|
39175
|
-
};
|
|
39176
|
-
}).sort((left, right) => (left.startedAt ?? 0) - (right.startedAt ?? 0));
|
|
39177
|
-
};
|
|
39178
|
-
var buildVoiceSessionObservabilityReport = async (options) => {
|
|
39179
|
-
const record = await buildVoiceOperationsRecord({
|
|
39180
|
-
audit: options.audit,
|
|
39181
|
-
evaluation: options.evaluation,
|
|
39182
|
-
events: options.events,
|
|
39183
|
-
integrationEvents: options.integrationEvents,
|
|
39184
|
-
redact: options.redact,
|
|
39185
|
-
reviews: options.reviews,
|
|
39186
|
-
sessionId: options.sessionId,
|
|
39187
|
-
store: options.store,
|
|
39188
|
-
tasks: options.tasks
|
|
39189
|
-
});
|
|
39190
|
-
const failureReplay = buildVoiceFailureReplay(record, {
|
|
39191
|
-
operationsRecordHref: resolveHref(options.operationsRecordHref, options.sessionId)
|
|
39192
|
-
});
|
|
39193
|
-
const incidentMarkdown = renderVoiceOperationsRecordIncidentMarkdown(record);
|
|
39194
|
-
const statuses = [
|
|
39195
|
-
record.status,
|
|
39196
|
-
failureReplay.status === "failed" ? "failed" : failureReplay.status === "degraded" ? "warning" : "healthy"
|
|
39197
|
-
];
|
|
39198
|
-
const status = statuses.includes("failed") ? "failed" : statuses.includes("warning") ? "warning" : "healthy";
|
|
39199
|
-
return {
|
|
39200
|
-
checkedAt: Date.now(),
|
|
39201
|
-
failureReplay,
|
|
39202
|
-
incidentMarkdown,
|
|
39203
|
-
links: buildLinks(options),
|
|
39204
|
-
record,
|
|
39205
|
-
sessionId: options.sessionId,
|
|
39206
|
-
status,
|
|
39207
|
-
summary: {
|
|
39208
|
-
durationMs: record.summary.callDurationMs,
|
|
39209
|
-
errors: record.summary.errorCount,
|
|
39210
|
-
events: record.summary.eventCount,
|
|
39211
|
-
fallbacks: record.providerDecisionSummary.fallbacks,
|
|
39212
|
-
guardrailBlocks: record.guardrails.blocked,
|
|
39213
|
-
handoffs: record.handoffs.length,
|
|
39214
|
-
providerRecoveryStatus: record.providerDecisionSummary.recoveryStatus,
|
|
39215
|
-
providers: record.providerDecisionSummary.providers,
|
|
39216
|
-
telephonyMediaEvents: record.telephonyMedia.total,
|
|
39217
|
-
toolCalls: record.tools.length,
|
|
39218
|
-
turns: record.summary.turnCount
|
|
39219
|
-
},
|
|
39220
|
-
turns: buildTurnWaterfalls(record)
|
|
39221
|
-
};
|
|
39222
|
-
};
|
|
39223
|
-
var renderLinks = (links) => links.length === 0 ? "" : `<div class="actions">${links.map((link) => `<a href="${escapeHtml59(link.href)}">${escapeHtml59(link.label)}</a>`).join("")}</div>`;
|
|
39224
|
-
var renderTurns = (turns) => turns.length === 0 ? '<p class="muted">No turn-level events recorded yet.</p>' : turns.map((turn) => `<article class="turn"><header><strong>${escapeHtml59(turn.turnId)}</strong><span>${formatMs6(turn.durationMs)}</span></header><dl><div><dt>Transcripts</dt><dd>${String(turn.transcripts)}</dd></div><div><dt>Assistant</dt><dd>${String(turn.assistantReplies)}</dd></div><div><dt>Tools</dt><dd>${String(turn.toolCalls)}</dd></div><div><dt>Providers</dt><dd>${String(turn.providerDecisions)}</dd></div><div><dt>Errors</dt><dd>${String(turn.errors)}</dd></div></dl><table><thead><tr><th>Offset</th><th>Type</th><th>Stage</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${turn.stages.map((stage) => `<tr><td>+${String(stage.offsetMs)}ms</td><td>${escapeHtml59(stage.type)}</td><td>${escapeHtml59(stage.label)}</td><td>${escapeHtml59(stage.provider ?? "")}</td><td>${escapeHtml59(stage.status ?? "")}</td><td>${formatMs6(stage.elapsedMs)}</td></tr>`).join("")}</tbody></table></article>`).join("");
|
|
39225
|
-
var renderVoiceSessionObservabilityMarkdown = (report) => `# Voice session observability: ${report.sessionId}
|
|
39226
|
-
|
|
39227
|
-
Status: ${report.status}
|
|
39228
|
-
|
|
39229
|
-
- Events: ${report.summary.events}
|
|
39230
|
-
- Turns: ${report.summary.turns}
|
|
39231
|
-
- Errors: ${report.summary.errors}
|
|
39232
|
-
- Duration: ${formatMs6(report.summary.durationMs)}
|
|
39233
|
-
- Providers: ${report.summary.providers.join(", ") || "none"}
|
|
39234
|
-
- Provider recovery: ${report.summary.providerRecoveryStatus}
|
|
39235
|
-
- Fallbacks: ${report.summary.fallbacks}
|
|
39236
|
-
- Tool calls: ${report.summary.toolCalls}
|
|
39237
|
-
- Handoffs: ${report.summary.handoffs}
|
|
39238
|
-
- Guardrail blocks: ${report.summary.guardrailBlocks}
|
|
39239
|
-
- Telephony media events: ${report.summary.telephonyMediaEvents}
|
|
39240
|
-
|
|
39241
|
-
## Links
|
|
39242
|
-
|
|
39243
|
-
${report.links.length ? report.links.map((link) => `- [${link.label}](${link.href})`).join(`
|
|
39244
|
-
`) : "- none"}
|
|
39245
|
-
|
|
39246
|
-
## Turn Waterfalls
|
|
39247
|
-
|
|
39248
|
-
${report.turns.length ? report.turns.map((turn) => `### ${turn.turnId}
|
|
39249
|
-
|
|
39250
|
-
- Duration: ${formatMs6(turn.durationMs)}
|
|
39251
|
-
- Transcripts: ${turn.transcripts}
|
|
39252
|
-
- Assistant replies: ${turn.assistantReplies}
|
|
39253
|
-
- Tool calls: ${turn.toolCalls}
|
|
39254
|
-
- Provider decisions: ${turn.providerDecisions}
|
|
39255
|
-
- Errors: ${turn.errors}
|
|
39256
|
-
|
|
39257
|
-
${turn.stages.map((stage) => `- +${stage.offsetMs}ms ${stage.type}: ${stage.label}${stage.provider ? ` (${stage.provider})` : ""}${stage.status ? ` [${stage.status}]` : ""}`).join(`
|
|
39258
|
-
`)}`).join(`
|
|
39259
|
-
|
|
39260
|
-
`) : "No turn-level events recorded."}
|
|
39261
|
-
|
|
39262
|
-
## Incident Handoff
|
|
39263
|
-
|
|
39264
|
-
${report.incidentMarkdown}`;
|
|
39265
|
-
var renderVoiceSessionObservabilityHTML = (report, options = {}) => `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml59(options.title ?? "Voice Session Observability")}</title><style>body{background:#0d1412;color:#f7f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #425046;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.actions{display:flex;flex-wrap:wrap;gap:10px;margin:18px 0}.actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:22px 0}.card,.turn,.incident{background:#17201c;border:1px solid #2e3c35;border-radius:20px;padding:16px}.card span,.muted,dt{color:#a8b4ad}.card strong{display:block;font-size:2rem}section{margin-top:30px}.turn{margin:16px 0}.turn header{align-items:center;display:flex;justify-content:space-between;gap:14px}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));margin:14px 0}dd{font-weight:900;margin:3px 0 0}table{border-collapse:collapse;margin-top:14px;width:100%}td,th{border-top:1px solid #2e3c35;padding:10px;text-align:left}pre{background:#08100d;border:1px solid #2e3c35;border-radius:16px;color:#d9f99d;overflow:auto;padding:14px}@media(max-width:760px){main{padding:20px}table{font-size:.9rem}}</style></head><body><main><header><p class="eyebrow">Session observability</p><h1>${escapeHtml59(report.sessionId)}</h1><p class="status ${escapeHtml59(report.status)}">${escapeHtml59(report.status)}</p>${renderLinks(report.links)}<p class="muted">One support/debug report across trace timeline, operations record, provider recovery, turn waterfalls, guardrails, tools, handoffs, failure replay, and incident handoff.</p></header><section class="grid"><article class="card"><span>Events</span><strong>${String(report.summary.events)}</strong></article><article class="card"><span>Turns</span><strong>${String(report.summary.turns)}</strong></article><article class="card"><span>Errors</span><strong>${String(report.summary.errors)}</strong></article><article class="card"><span>Duration</span><strong>${formatMs6(report.summary.durationMs)}</strong></article><article class="card"><span>Fallbacks</span><strong>${String(report.summary.fallbacks)}</strong></article><article class="card"><span>Tools</span><strong>${String(report.summary.toolCalls)}</strong></article><article class="card"><span>Handoffs</span><strong>${String(report.summary.handoffs)}</strong></article><article class="card"><span>Guardrails blocked</span><strong>${String(report.summary.guardrailBlocks)}</strong></article><article class="card"><span>Telephony media</span><strong>${String(report.summary.telephonyMediaEvents)}</strong></article></section><section><h2>Turn Waterfalls</h2>${renderTurns(report.turns)}</section><section class="incident"><h2>Incident Handoff</h2><pre><code>${escapeHtml59(report.incidentMarkdown)}</code></pre></section></main></body></html>`;
|
|
39266
|
-
var routeSessionId = (params) => typeof params.sessionId === "string" ? params.sessionId : "";
|
|
39267
|
-
var createVoiceSessionObservabilityRoutes = (options) => {
|
|
39268
|
-
const path = options.path ?? "/api/voice/session-observability/:sessionId";
|
|
39269
|
-
const htmlPath = options.htmlPath ?? "/voice/session-observability/:sessionId";
|
|
39270
|
-
const incidentPath = options.incidentPath ?? "/api/voice/session-observability/:sessionId/incident.md";
|
|
39271
|
-
const title = options.title ?? "AbsoluteJS Voice Session Observability";
|
|
39272
|
-
const routes = new Elysia62({
|
|
39273
|
-
name: options.name ?? "absolutejs-voice-session-observability"
|
|
39274
|
-
});
|
|
39275
|
-
const build = (sessionId) => buildVoiceSessionObservabilityReport({
|
|
39276
|
-
audit: options.audit,
|
|
39277
|
-
callDebuggerHref: options.callDebuggerHref,
|
|
39278
|
-
customLinks: options.customLinks,
|
|
39279
|
-
evaluation: options.evaluation,
|
|
39280
|
-
events: options.events,
|
|
39281
|
-
incidentMarkdownHref: options.incidentMarkdownHref ?? (incidentPath === false ? false : incidentPath),
|
|
39282
|
-
integrationEvents: options.integrationEvents,
|
|
39283
|
-
operationsRecordHref: options.operationsRecordHref,
|
|
39284
|
-
redact: options.redact,
|
|
39285
|
-
reviews: options.reviews,
|
|
39286
|
-
sessionId,
|
|
39287
|
-
store: options.store,
|
|
39288
|
-
tasks: options.tasks,
|
|
39289
|
-
traceTimelineHref: options.traceTimelineHref
|
|
39290
|
-
});
|
|
39291
|
-
routes.get(path, async ({ params }) => Response.json(await build(routeSessionId(params))));
|
|
39292
|
-
if (htmlPath !== false) {
|
|
39293
|
-
routes.get(htmlPath, async ({ params }) => {
|
|
39294
|
-
const report = await build(routeSessionId(params));
|
|
39295
|
-
const body = await (options.render ?? ((input) => renderVoiceSessionObservabilityHTML(input, { title })))(report);
|
|
39296
|
-
return new Response(body, {
|
|
39297
|
-
headers: {
|
|
39298
|
-
"content-type": "text/html; charset=utf-8",
|
|
39299
|
-
...options.headers
|
|
39300
|
-
}
|
|
39301
|
-
});
|
|
39302
|
-
});
|
|
39303
|
-
}
|
|
39304
|
-
if (incidentPath !== false) {
|
|
39305
|
-
routes.get(incidentPath, async ({ params }) => {
|
|
39306
|
-
const report = await build(routeSessionId(params));
|
|
39307
|
-
const body = await (options.renderIncidentMarkdown ?? renderVoiceSessionObservabilityMarkdown)(report);
|
|
39308
|
-
return new Response(body, {
|
|
39309
|
-
headers: {
|
|
39310
|
-
"content-type": "text/markdown; charset=utf-8",
|
|
39311
|
-
...options.headers
|
|
39312
|
-
}
|
|
39313
|
-
});
|
|
39314
|
-
});
|
|
39315
|
-
}
|
|
39316
|
-
return routes;
|
|
39317
|
-
};
|
|
39318
39507
|
// src/incidentBundle.ts
|
|
39319
39508
|
import { Elysia as Elysia63 } from "elysia";
|
|
39320
39509
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
@@ -42399,6 +42588,7 @@ var buildVoiceProofPackInput = async (options) => {
|
|
|
42399
42588
|
providerSlo,
|
|
42400
42589
|
runId: options.runId,
|
|
42401
42590
|
sections: options.sections,
|
|
42591
|
+
sessionObservabilityReports: supportBundle?.sessionObservabilityReports ?? options.sessionObservabilityReports,
|
|
42402
42592
|
sessionSnapshots: supportBundle?.sessionSnapshots ?? options.sessionSnapshots
|
|
42403
42593
|
};
|
|
42404
42594
|
};
|
|
@@ -42524,9 +42714,13 @@ var createVoiceProofPackOperationsRecordSection = (records, options = {}) => {
|
|
|
42524
42714
|
var createVoiceProofPackSupportBundleSection = (input) => {
|
|
42525
42715
|
const snapshots = input.sessionSnapshots ?? [];
|
|
42526
42716
|
const debuggerReports = input.callDebuggerReports ?? [];
|
|
42717
|
+
const observabilityReports = input.sessionObservabilityReports ?? [];
|
|
42527
42718
|
const failedSnapshots = snapshots.filter((snapshot) => snapshot.status === "fail").length;
|
|
42528
42719
|
const failedDebuggerReports = debuggerReports.filter((report) => report.status === "failed").length;
|
|
42529
|
-
const
|
|
42720
|
+
const failedObservabilityReports = observabilityReports.filter((report) => report.status === "failed").length;
|
|
42721
|
+
const warnings = snapshots.filter((snapshot) => snapshot.status === "warn").length + debuggerReports.filter((report) => report.status === "warning").length + observabilityReports.filter((report) => report.status === "warning").length;
|
|
42722
|
+
const turnWaterfalls = observabilityReports.reduce((total, report) => total + report.turns.length, 0);
|
|
42723
|
+
const fallbacks = observabilityReports.reduce((total, report) => total + report.summary.fallbacks, 0);
|
|
42530
42724
|
return {
|
|
42531
42725
|
evidence: [
|
|
42532
42726
|
numberEvidence("Session snapshots", snapshots.length, {
|
|
@@ -42535,20 +42729,34 @@ var createVoiceProofPackSupportBundleSection = (input) => {
|
|
|
42535
42729
|
numberEvidence("Call debugger reports", debuggerReports.length, {
|
|
42536
42730
|
passWhenPositive: true
|
|
42537
42731
|
}),
|
|
42732
|
+
numberEvidence("Session observability reports", observabilityReports.length, {
|
|
42733
|
+
passWhenPositive: true
|
|
42734
|
+
}),
|
|
42735
|
+
numberEvidence("Turn waterfalls", turnWaterfalls, {
|
|
42736
|
+
passWhenPositive: true
|
|
42737
|
+
}),
|
|
42538
42738
|
numberEvidence("Failed snapshots", failedSnapshots, {
|
|
42539
42739
|
failWhenPositive: true
|
|
42540
42740
|
}),
|
|
42541
42741
|
numberEvidence("Failed debugger reports", failedDebuggerReports, {
|
|
42542
42742
|
failWhenPositive: true
|
|
42543
42743
|
}),
|
|
42744
|
+
numberEvidence("Failed observability reports", failedObservabilityReports, {
|
|
42745
|
+
failWhenPositive: true
|
|
42746
|
+
}),
|
|
42747
|
+
{
|
|
42748
|
+
label: "Provider fallbacks in observability reports",
|
|
42749
|
+
status: fallbacks > 0 ? "warn" : "pass",
|
|
42750
|
+
value: fallbacks
|
|
42751
|
+
},
|
|
42544
42752
|
{
|
|
42545
42753
|
label: "Warning support artifacts",
|
|
42546
42754
|
status: warnings > 0 ? "warn" : "pass",
|
|
42547
42755
|
value: warnings
|
|
42548
42756
|
}
|
|
42549
42757
|
],
|
|
42550
|
-
status: failedSnapshots > 0 || failedDebuggerReports > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
|
|
42551
|
-
summary: "Support artifacts that make
|
|
42758
|
+
status: failedSnapshots > 0 || failedDebuggerReports > 0 || failedObservabilityReports > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
|
|
42759
|
+
summary: "Support artifacts that make calls debuggable, including turn waterfalls and per-call observability links.",
|
|
42552
42760
|
title: input.title ?? "Support bundle"
|
|
42553
42761
|
};
|
|
42554
42762
|
};
|
|
@@ -42566,9 +42774,10 @@ var buildDerivedProofPackSections = (input) => [
|
|
|
42566
42774
|
href: (sessionId) => input.productionReadiness?.links.operationsRecords ? `${input.productionReadiness.links.operationsRecords}/${encodeURIComponent(sessionId)}` : undefined
|
|
42567
42775
|
})
|
|
42568
42776
|
] : [],
|
|
42569
|
-
...input.sessionSnapshots?.length || input.callDebuggerReports?.length ? [
|
|
42777
|
+
...input.sessionSnapshots?.length || input.callDebuggerReports?.length || input.sessionObservabilityReports?.length ? [
|
|
42570
42778
|
createVoiceProofPackSupportBundleSection({
|
|
42571
42779
|
callDebuggerReports: input.callDebuggerReports,
|
|
42780
|
+
sessionObservabilityReports: input.sessionObservabilityReports,
|
|
42572
42781
|
sessionSnapshots: input.sessionSnapshots
|
|
42573
42782
|
})
|
|
42574
42783
|
] : [],
|
|
@@ -43093,6 +43302,7 @@ export {
|
|
|
43093
43302
|
evaluateVoiceTelephonyWebhookNormalizationEvidence,
|
|
43094
43303
|
evaluateVoiceTelephonyContract,
|
|
43095
43304
|
evaluateVoiceSimulationSuiteEvidence,
|
|
43305
|
+
evaluateVoiceSessionObservabilityEvidence,
|
|
43096
43306
|
evaluateVoiceRealtimeProviderContractEvidence,
|
|
43097
43307
|
evaluateVoiceRealtimeChannelEvidence,
|
|
43098
43308
|
evaluateVoiceQuality,
|
|
@@ -43487,6 +43697,8 @@ export {
|
|
|
43487
43697
|
buildVoiceRealCallProfileHistoryReportFromStore,
|
|
43488
43698
|
buildVoiceRealCallProfileHistoryReport,
|
|
43489
43699
|
buildVoiceRealCallProfileEvidenceFromTraceEvents,
|
|
43700
|
+
buildVoiceRealCallProfileEvidenceFromRuntimeSurface,
|
|
43701
|
+
buildVoiceRealCallProfileEvidenceFromRuntimeProviderRoles,
|
|
43490
43702
|
buildVoiceRealCallProfileEvidenceFromReconnectProofReports,
|
|
43491
43703
|
buildVoiceRealCallProfileDefaults,
|
|
43492
43704
|
buildVoiceRealCallEvidenceRuntimeWorkerReadinessCheck,
|
|
@@ -43555,6 +43767,7 @@ export {
|
|
|
43555
43767
|
assertVoiceTelephonyWebhookNormalizationEvidence,
|
|
43556
43768
|
assertVoiceSloCalibration,
|
|
43557
43769
|
assertVoiceSimulationSuiteEvidence,
|
|
43770
|
+
assertVoiceSessionObservabilityEvidence,
|
|
43558
43771
|
assertVoiceRealtimeProviderContractEvidence,
|
|
43559
43772
|
assertVoiceRealtimeChannelEvidence,
|
|
43560
43773
|
assertVoiceProviderStackEvidence,
|