@absolutejs/voice 0.0.22-beta.193 → 0.0.22-beta.195

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/index.js CHANGED
@@ -7756,7 +7756,7 @@ var createVoiceAgentSquad = (options) => {
7756
7756
  targetAgentId: nextAgent.id,
7757
7757
  turn: input.turn
7758
7758
  });
7759
- await appendVoiceAgentSquadHandoff({
7759
+ const handoff = await appendVoiceAgentSquadHandoff({
7760
7760
  agentId: options.id,
7761
7761
  fromAgentId: agent.id,
7762
7762
  handoffs,
@@ -7782,17 +7782,54 @@ var createVoiceAgentSquad = (options) => {
7782
7782
  sessionId: input.session.id,
7783
7783
  toAgentId: nextAgent.id
7784
7784
  });
7785
- messages.push({
7785
+ const summaryMessage = {
7786
7786
  content: handoffSummary ?? handoffReason ?? `Handoff to ${nextAgent.id}`,
7787
7787
  metadata,
7788
7788
  name: nextAgent.id,
7789
7789
  role: "system"
7790
+ };
7791
+ messages.push(summaryMessage);
7792
+ const contextPolicy = await options.contextPolicy?.({
7793
+ context: input.context,
7794
+ fromAgentId: agent.id,
7795
+ handoff,
7796
+ messages,
7797
+ session: input.session,
7798
+ summaryMessage,
7799
+ targetAgent: nextAgent,
7800
+ turn: input.turn
7801
+ });
7802
+ if (contextPolicy?.metadata && Object.keys(contextPolicy.metadata).length > 0) {
7803
+ handoff.metadata = {
7804
+ ...handoff.metadata,
7805
+ ...contextPolicy.metadata
7806
+ };
7807
+ const latest = handoffs.at(-1);
7808
+ if (latest === handoff) {
7809
+ latest.metadata = handoff.metadata;
7810
+ }
7811
+ }
7812
+ await appendVoiceAgentTrace({
7813
+ agentId: options.id,
7814
+ event: {
7815
+ fromAgentId: handoff.fromAgentId,
7816
+ messageCount: messages.length,
7817
+ nextMessageCount: contextPolicy?.messages?.length ?? messages.length,
7818
+ status: contextPolicy ? "applied" : "default",
7819
+ summaryIncluded: (contextPolicy?.messages ?? messages).some((message) => message === summaryMessage),
7820
+ targetAgentId: nextAgent.id
7821
+ },
7822
+ session: input.session,
7823
+ trace: options.trace,
7824
+ turn: input.turn,
7825
+ type: "agent.context"
7790
7826
  });
7791
7827
  agent = nextAgent;
7792
7828
  agentId = nextAgent.id;
7793
7829
  result = await agent.run({
7794
7830
  ...input,
7795
- messages
7831
+ messages: contextPolicy?.messages ?? messages,
7832
+ system: contextPolicy?.system ?? input.system
7796
7833
  });
7797
7834
  toolResults.push(...result.toolResults);
7798
7835
  }
@@ -9503,6 +9540,8 @@ var renderTraceEventMarkdown = (event, startedAt) => {
9503
9540
  return event.payload.text ? `${label} assistant "${formatTraceValue(event.payload.text)}"` : `${label} ${formatTraceValue(event.payload.status)}`;
9504
9541
  case "agent.tool":
9505
9542
  return `${label} ${formatTraceValue(event.payload.toolName)} ${formatTraceValue(event.payload.status)}`;
9543
+ case "agent.context":
9544
+ return `${label} ${formatTraceValue(event.payload.fromAgentId)} -> ${formatTraceValue(event.payload.targetAgentId)} ${formatTraceValue(event.payload.status)}`;
9506
9545
  case "agent.handoff":
9507
9546
  return `${label} ${formatTraceValue(event.payload.fromAgentId)} -> ${formatTraceValue(event.payload.targetAgentId)}`;
9508
9547
  case "session.error":
@@ -12673,6 +12712,20 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
12673
12712
  return routes;
12674
12713
  };
12675
12714
  // src/dataControl.ts
12715
+ import { Elysia as Elysia15 } from "elysia";
12716
+ var voiceComplianceRedactionDefaults = {
12717
+ keys: [
12718
+ "apiKey",
12719
+ "authorization",
12720
+ "email",
12721
+ "password",
12722
+ "phone",
12723
+ "secret",
12724
+ "token"
12725
+ ],
12726
+ redactEmails: true,
12727
+ redactPhoneNumbers: true
12728
+ };
12676
12729
  var allRetentionScopes = [
12677
12730
  "auditDeliveries",
12678
12731
  "campaigns",
@@ -12886,17 +12939,269 @@ var applyVoiceDataRetentionPolicy = async (options) => {
12886
12939
  return report;
12887
12940
  };
12888
12941
  var buildVoiceDataRetentionPlan = (options) => applyVoiceDataRetentionPolicy({ ...options, dryRun: true });
12942
+ var getBooleanQuery = (value) => value === true || value === "true" || value === "1";
12943
+ var getNumberQuery = (value) => {
12944
+ const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : undefined;
12945
+ return typeof parsed === "number" && Number.isFinite(parsed) ? parsed : undefined;
12946
+ };
12947
+ var parseRetentionScopes = (value) => {
12948
+ if (typeof value !== "string" || !value.trim()) {
12949
+ return;
12950
+ }
12951
+ const allowed = new Set(allRetentionScopes);
12952
+ return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
12953
+ };
12954
+ var escapeHtml17 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12955
+ var buildStorageSurfaces = (options) => [
12956
+ {
12957
+ configured: Boolean(options.session ?? options.sessions),
12958
+ control: "session",
12959
+ name: "Sessions",
12960
+ selfHosted: true
12961
+ },
12962
+ {
12963
+ configured: Boolean(options.traces),
12964
+ control: "audit",
12965
+ name: "Trace events",
12966
+ selfHosted: true
12967
+ },
12968
+ {
12969
+ configured: Boolean(options.audit),
12970
+ control: "audit",
12971
+ name: "Audit events",
12972
+ selfHosted: true
12973
+ },
12974
+ {
12975
+ configured: Boolean(options.reviews),
12976
+ control: "artifact",
12977
+ name: "Call reviews",
12978
+ selfHosted: true
12979
+ },
12980
+ {
12981
+ configured: Boolean(options.tasks),
12982
+ control: "workflow",
12983
+ name: "Ops tasks",
12984
+ selfHosted: true
12985
+ },
12986
+ {
12987
+ configured: Boolean(options.events),
12988
+ control: "workflow",
12989
+ name: "Integration events",
12990
+ selfHosted: true
12991
+ },
12992
+ {
12993
+ configured: Boolean(options.campaigns),
12994
+ control: "workflow",
12995
+ name: "Campaign records",
12996
+ selfHosted: true
12997
+ },
12998
+ {
12999
+ configured: Boolean(options.auditDeliveries ?? options.traceDeliveries),
13000
+ control: "queue",
13001
+ name: "Audit/trace delivery queues",
13002
+ selfHosted: true
13003
+ },
13004
+ {
13005
+ configured: Boolean(options.incidentBundles),
13006
+ control: "artifact",
13007
+ name: "Incident bundles",
13008
+ selfHosted: true
13009
+ }
13010
+ ];
13011
+ var defaultProviderKeys = [
13012
+ {
13013
+ env: "OPENAI_API_KEY",
13014
+ name: "OpenAI",
13015
+ recommendation: "Keep provider keys server-side, scoped per environment, and never expose them to browser voice clients.",
13016
+ required: false
13017
+ },
13018
+ {
13019
+ env: "ANTHROPIC_API_KEY",
13020
+ name: "Anthropic",
13021
+ recommendation: "Use least-privilege project keys and route all requests through your AbsoluteJS server.",
13022
+ required: false
13023
+ },
13024
+ {
13025
+ env: "GEMINI_API_KEY",
13026
+ name: "Gemini",
13027
+ recommendation: "Use server-owned credentials and redact prompts/tool payloads before support export.",
13028
+ required: false
13029
+ },
13030
+ {
13031
+ env: "DEEPGRAM_API_KEY",
13032
+ name: "Deepgram",
13033
+ recommendation: "Keep STT credentials server-side and pair transcript exports with PII redaction.",
13034
+ required: false
13035
+ }
13036
+ ];
13037
+ var resolveDataControlRedaction = (redact) => redact === false ? undefined : redact === true || redact === undefined ? voiceComplianceRedactionDefaults : redact;
13038
+ var createVoiceZeroRetentionPolicy = (options) => ({
13039
+ ...options,
13040
+ beforeOrAt: options.beforeOrAt ?? Date.now(),
13041
+ dryRun: options.dryRun ?? true,
13042
+ scopes: options.scopes ?? allRetentionScopes
13043
+ });
13044
+ var buildVoiceDataControlReport = async (options) => {
13045
+ const redaction = resolveDataControlRedaction(options.redact);
13046
+ const retentionPlan = await buildVoiceDataRetentionPlan({
13047
+ ...options,
13048
+ ...options.retention ?? {},
13049
+ auditDeliveries: options.auditDeliveries,
13050
+ traceDeliveries: options.traceDeliveries
13051
+ });
13052
+ const auditExport = options.audit ? await exportVoiceAuditTrail({
13053
+ filter: options.auditFilter,
13054
+ redact: redaction,
13055
+ store: options.audit
13056
+ }) : undefined;
13057
+ return {
13058
+ auditExport,
13059
+ checkedAt: Date.now(),
13060
+ redaction: {
13061
+ defaults: voiceComplianceRedactionDefaults,
13062
+ enabled: Boolean(redaction)
13063
+ },
13064
+ retentionPlan,
13065
+ storage: buildStorageSurfaces(options),
13066
+ providerKeys: options.providerKeys ?? defaultProviderKeys,
13067
+ zeroRetentionAvailable: true
13068
+ };
13069
+ };
13070
+ var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${escapeHtml17(scope.scope)}</td><td>${scope.scannedCount}</td><td>${scope.deletedCount}</td><td>${escapeHtml17(scope.skippedReason ?? "")}</td><td><code>${escapeHtml17(scope.deletedIds.join(", "))}</code></td></tr>`).join("");
13071
+ var renderVoiceDataControlHTML = (report, options = {}) => {
13072
+ const title = options.title ?? "Voice Data Control";
13073
+ const storageRows = report.storage.map((surface) => `<tr><td>${escapeHtml17(surface.name)}</td><td>${surface.configured ? "Configured" : "Missing"}</td><td>${escapeHtml17(surface.control)}</td><td>${surface.selfHosted ? "Yes" : "No"}</td></tr>`).join("");
13074
+ const keyRows = report.providerKeys.map((key) => `<tr><td>${escapeHtml17(key.name)}</td><td><code>${escapeHtml17(key.env ?? "n/a")}</code></td><td>${key.required ? "Required" : "Optional"}</td><td>${escapeHtml17(key.recommendation)}</td></tr>`).join("");
13075
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml17(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>${escapeHtml17(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>`;
13076
+ };
13077
+ var renderVoiceDataControlMarkdown = (report, options = {}) => [
13078
+ `# ${options.title ?? "Voice Data Control"}`,
13079
+ "",
13080
+ `Checked: ${new Date(report.checkedAt).toISOString()}`,
13081
+ `Redaction: ${report.redaction.enabled ? "enabled" : "disabled"}`,
13082
+ `Retention dry-run deletes: ${report.retentionPlan.deletedCount}`,
13083
+ `Audit export events: ${report.auditExport?.events.length ?? 0}`,
13084
+ "",
13085
+ "## Customer-Owned Storage",
13086
+ "",
13087
+ ...report.storage.map((surface) => `- ${surface.name}: ${surface.configured ? "configured" : "missing"} (${surface.control})`),
13088
+ "",
13089
+ "## Retention Plan",
13090
+ "",
13091
+ ...report.retentionPlan.scopes.map((scope) => `- ${scope.scope}: scanned ${scope.scannedCount}, would delete ${scope.deletedCount}${scope.skippedReason ? `, skipped=${scope.skippedReason}` : ""}`),
13092
+ "",
13093
+ "## Provider Keys",
13094
+ "",
13095
+ ...report.providerKeys.map((key) => `- ${key.name}${key.env ? ` (${key.env})` : ""}: ${key.recommendation}`)
13096
+ ].join(`
13097
+ `);
13098
+ var buildRetentionPolicyFromQuery = (query, options) => ({
13099
+ ...options,
13100
+ before: getNumberQuery(query.before),
13101
+ beforeOrAt: getNumberQuery(query.beforeOrAt),
13102
+ dryRun: !getBooleanQuery(query.apply),
13103
+ limit: getNumberQuery(query.limit),
13104
+ scopes: parseRetentionScopes(query.scopes),
13105
+ traceFilter: typeof query.sessionId === "string" && query.sessionId.trim() ? { sessionId: query.sessionId } : undefined
13106
+ });
13107
+ var parseRetentionPolicyBody = (body, options, dryRun) => {
13108
+ const input = body && typeof body === "object" ? body : {};
13109
+ return {
13110
+ ...options,
13111
+ before: getNumberQuery(input.before),
13112
+ beforeOrAt: getNumberQuery(input.beforeOrAt),
13113
+ dryRun,
13114
+ limit: getNumberQuery(input.limit),
13115
+ scopes: parseRetentionScopes(input.scopes),
13116
+ traceFilter: typeof input.sessionId === "string" && input.sessionId.trim() ? { sessionId: input.sessionId } : undefined
13117
+ };
13118
+ };
13119
+ var createVoiceDataControlRoutes = (options) => {
13120
+ const path = options.path ?? "/data-control";
13121
+ const title = options.title ?? "AbsoluteJS Voice Data Control";
13122
+ const routes = new Elysia15({
13123
+ name: options.name ?? "absolutejs-voice-data-control"
13124
+ });
13125
+ routes.get(path, async ({ query }) => {
13126
+ const report = await buildVoiceDataControlReport({
13127
+ ...options,
13128
+ retention: buildRetentionPolicyFromQuery(query, options)
13129
+ });
13130
+ return new Response(renderVoiceDataControlHTML(report, { title }), {
13131
+ headers: {
13132
+ "Content-Type": "text/html; charset=utf-8",
13133
+ ...options.headers
13134
+ }
13135
+ });
13136
+ });
13137
+ routes.get(`${path}.json`, async ({ query }) => buildVoiceDataControlReport({
13138
+ ...options,
13139
+ retention: buildRetentionPolicyFromQuery(query, options)
13140
+ }));
13141
+ routes.get(`${path}.md`, async ({ query }) => {
13142
+ const report = await buildVoiceDataControlReport({
13143
+ ...options,
13144
+ retention: buildRetentionPolicyFromQuery(query, options)
13145
+ });
13146
+ return new Response(renderVoiceDataControlMarkdown(report, { title }), {
13147
+ headers: {
13148
+ "Content-Type": "text/markdown; charset=utf-8",
13149
+ ...options.headers
13150
+ }
13151
+ });
13152
+ });
13153
+ routes.post(`${path}/retention/plan`, async ({ body }) => buildVoiceDataRetentionPlan(parseRetentionPolicyBody(body, options, true)));
13154
+ routes.post(`${path}/retention/apply`, async ({ body, set }) => {
13155
+ const input = body && typeof body === "object" ? body : {};
13156
+ if (input.confirm !== "apply-retention-policy") {
13157
+ set.status = 400;
13158
+ return {
13159
+ error: 'Refusing to apply retention without confirm="apply-retention-policy". Use /retention/plan first.'
13160
+ };
13161
+ }
13162
+ return applyVoiceDataRetentionPolicy(parseRetentionPolicyBody(body, options, false));
13163
+ });
13164
+ routes.get(`${path}/audit.json`, async () => options.audit ? exportVoiceAuditTrail({
13165
+ redact: resolveDataControlRedaction(options.redact),
13166
+ store: options.audit
13167
+ }) : { events: [], exportedAt: Date.now(), redacted: false });
13168
+ routes.get(`${path}/audit.md`, async () => {
13169
+ const events = options.audit ? await options.audit.list() : [];
13170
+ return new Response(renderVoiceAuditMarkdown(events, {
13171
+ redact: resolveDataControlRedaction(options.redact),
13172
+ title: `${title} Audit Export`
13173
+ }), {
13174
+ headers: {
13175
+ "Content-Type": "text/markdown; charset=utf-8",
13176
+ ...options.headers
13177
+ }
13178
+ });
13179
+ });
13180
+ routes.get(`${path}/audit.html`, async () => {
13181
+ const events = options.audit ? await options.audit.list() : [];
13182
+ return new Response(renderVoiceAuditHTML(events, {
13183
+ redact: resolveDataControlRedaction(options.redact),
13184
+ title: `${title} Audit Export`
13185
+ }), {
13186
+ headers: {
13187
+ "Content-Type": "text/html; charset=utf-8",
13188
+ ...options.headers
13189
+ }
13190
+ });
13191
+ });
13192
+ return routes;
13193
+ };
12889
13194
  // src/evalRoutes.ts
12890
- import { Elysia as Elysia17 } from "elysia";
13195
+ import { Elysia as Elysia18 } from "elysia";
12891
13196
  import { mkdir as mkdir2 } from "fs/promises";
12892
13197
  import { dirname as dirname2 } from "path";
12893
13198
 
12894
13199
  // src/qualityRoutes.ts
12895
- import { Elysia as Elysia16 } from "elysia";
13200
+ import { Elysia as Elysia17 } from "elysia";
12896
13201
 
12897
13202
  // src/handoffHealth.ts
12898
- import { Elysia as Elysia15 } from "elysia";
12899
- var escapeHtml17 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13203
+ import { Elysia as Elysia16 } from "elysia";
13204
+ var escapeHtml18 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12900
13205
  var getString6 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
12901
13206
  var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
12902
13207
  var increment3 = (record, key) => {
@@ -13014,10 +13319,10 @@ var renderActionSummary = (summary) => {
13014
13319
  return [
13015
13320
  '<section class="voice-handoff-health-columns">',
13016
13321
  "<article><h3>Actions</h3>",
13017
- actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml17(action)}: ${String(count)}</li>`).join("")}</ul>`,
13322
+ actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml18(action)}: ${String(count)}</li>`).join("")}</ul>`,
13018
13323
  "</article>",
13019
13324
  "<article><h3>Adapters</h3>",
13020
- adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml17(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
13325
+ adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml18(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
13021
13326
  "</article>",
13022
13327
  "</section>"
13023
13328
  ].join("");
@@ -13031,22 +13336,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
13031
13336
  summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
13032
13337
  '<div class="voice-handoff-health-events">',
13033
13338
  ...summary.events.map((event) => [
13034
- `<article class="${escapeHtml17(event.status)}">`,
13339
+ `<article class="${escapeHtml18(event.status)}">`,
13035
13340
  '<div class="voice-handoff-health-event-header">',
13036
- `<strong>${escapeHtml17(event.action ?? "handoff")}</strong>`,
13037
- `<span>${escapeHtml17(event.status)}</span>`,
13341
+ `<strong>${escapeHtml18(event.action ?? "handoff")}</strong>`,
13342
+ `<span>${escapeHtml18(event.status)}</span>`,
13038
13343
  "</div>",
13039
- `<p><small>${escapeHtml17(event.sessionId)}</small></p>`,
13040
- event.target ? `<p>Target: ${escapeHtml17(event.target)}</p>` : "",
13041
- event.reason ? `<p>Reason: ${escapeHtml17(event.reason)}</p>` : "",
13344
+ `<p><small>${escapeHtml18(event.sessionId)}</small></p>`,
13345
+ event.target ? `<p>Target: ${escapeHtml18(event.target)}</p>` : "",
13346
+ event.reason ? `<p>Reason: ${escapeHtml18(event.reason)}</p>` : "",
13042
13347
  event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
13043
13348
  "<li>",
13044
- `${escapeHtml17(delivery.adapterId)}: ${escapeHtml17(delivery.status)}`,
13045
- delivery.deliveredTo ? ` to ${escapeHtml17(delivery.deliveredTo)}` : "",
13046
- delivery.error ? ` (${escapeHtml17(delivery.error)})` : "",
13349
+ `${escapeHtml18(delivery.adapterId)}: ${escapeHtml18(delivery.status)}`,
13350
+ delivery.deliveredTo ? ` to ${escapeHtml18(delivery.deliveredTo)}` : "",
13351
+ delivery.error ? ` (${escapeHtml18(delivery.error)})` : "",
13047
13352
  "</li>"
13048
13353
  ].join("")).join("")}</ul>` : "",
13049
- event.replayHref ? `<p><a href="${escapeHtml17(event.replayHref)}">Open replay</a></p>` : "",
13354
+ event.replayHref ? `<p><a href="${escapeHtml18(event.replayHref)}">Open replay</a></p>` : "",
13050
13355
  "</article>"
13051
13356
  ].join("")),
13052
13357
  "</div>"
@@ -13078,7 +13383,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
13078
13383
  var createVoiceHandoffHealthRoutes = (options = {}) => {
13079
13384
  const path = options.path ?? "/api/voice-handoffs";
13080
13385
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
13081
- const routes = new Elysia15({
13386
+ const routes = new Elysia16({
13082
13387
  name: options.name ?? "absolutejs-voice-handoff-health"
13083
13388
  }).get(path, createVoiceHandoffHealthJSONHandler(options));
13084
13389
  if (htmlPath) {
@@ -13199,17 +13504,17 @@ var evaluateVoiceQuality = async (input) => {
13199
13504
  thresholds
13200
13505
  };
13201
13506
  };
13202
- var escapeHtml18 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13507
+ var escapeHtml19 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13203
13508
  var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
13204
13509
  var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
13205
13510
  var renderVoiceQualityHTML = (report, options = {}) => {
13206
- const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml18(metric.label)}</td><td>${escapeHtml18(formatMetricValue(metric))}</td><td>${escapeHtml18(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml18(key)}</code></td></tr>`).join("");
13207
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
13511
+ const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml19(metric.label)}</td><td>${escapeHtml19(formatMetricValue(metric))}</td><td>${escapeHtml19(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml19(key)}</code></td></tr>`).join("");
13512
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
13208
13513
  return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>AbsoluteJS Voice Quality</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}nav{display:flex;flex-wrap:wrap;gap:.5rem;margin:0 0 1.25rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;padding:.35rem .75rem;font-weight:800}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}table{border-collapse:collapse;width:100%;background:white;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}.pass td{border-left:4px solid #16a34a}.fail td{border-left:4px solid #dc2626}code{background:#f3f4f6;padding:.15rem .3rem;border-radius:.3rem}</style></head><body><main>${links}<h1>Voice quality gates</h1><p class="status ${report.status}">${report.status}</p><p>${report.eventCount} event(s) checked.</p><table><thead><tr><th>Metric</th><th>Actual</th><th>Threshold</th><th>Status</th><th>Key</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
13209
13514
  };
13210
13515
  var createVoiceQualityRoutes = (options) => {
13211
13516
  const path = options.path ?? "/quality";
13212
- const routes = new Elysia16({
13517
+ const routes = new Elysia17({
13213
13518
  name: options.name ?? "absolutejs-voice-quality"
13214
13519
  });
13215
13520
  const getReport = () => evaluateVoiceQuality({
@@ -13238,7 +13543,7 @@ var createVoiceQualityRoutes = (options) => {
13238
13543
  };
13239
13544
 
13240
13545
  // src/evalRoutes.ts
13241
- var escapeHtml19 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13546
+ var escapeHtml20 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13242
13547
  var rate2 = (count, total) => count / Math.max(1, total);
13243
13548
  var normalizeSearchText = (value) => value.trim().toLowerCase();
13244
13549
  var getString8 = (value) => typeof value === "string" ? value : undefined;
@@ -13546,7 +13851,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
13546
13851
  var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
13547
13852
  var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
13548
13853
  var renderVoiceEvalPrimitiveCopy = () => {
13549
- const snippet = escapeHtml19(`app.use(
13854
+ const snippet = escapeHtml20(`app.use(
13550
13855
  createVoiceEvalRoutes({
13551
13856
  path: '/evals',
13552
13857
  store: traceStore,
@@ -13567,44 +13872,44 @@ var renderVoiceEvalPrimitiveCopy = () => {
13567
13872
  };
13568
13873
  var renderVoiceEvalHTML = (report, options = {}) => {
13569
13874
  const title = options.title ?? "AbsoluteJS Voice Evals";
13570
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
13571
- const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml19(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>';
13875
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml20(link.href)}">${escapeHtml20(link.label)}</a>`).join("")}</nav>` : "";
13876
+ const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml20(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>';
13572
13877
  const sessions = report.sessions.length ? report.sessions.map((session) => {
13573
13878
  const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
13574
- return `<tr class="${session.status}"><td>${escapeHtml19(session.sessionId)}</td><td>${escapeHtml19(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml19(formatTime(session.endedAt))}</td><td>${escapeHtml19(failedMetrics || "none")}</td></tr>`;
13879
+ return `<tr class="${session.status}"><td>${escapeHtml20(session.sessionId)}</td><td>${escapeHtml20(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml20(formatTime(session.endedAt))}</td><td>${escapeHtml20(failedMetrics || "none")}</td></tr>`;
13575
13880
  }).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
13576
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(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>${escapeHtml19(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>`;
13881
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml20(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>${escapeHtml20(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>`;
13577
13882
  };
13578
13883
  var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
13579
13884
  const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
13580
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
13581
- const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml19(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
13582
- const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml19(id)}</li>`).join("") : "<li>none</li>";
13583
- const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml19(id)}</li>`).join("") : "<li>none</li>";
13584
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(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>${escapeHtml19(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml19(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml19(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>${escapeHtml19(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>`;
13885
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml20(link.href)}">${escapeHtml20(link.label)}</a>`).join("")}</nav>` : "";
13886
+ const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml20(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
13887
+ const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml20(id)}</li>`).join("") : "<li>none</li>";
13888
+ const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml20(id)}</li>`).join("") : "<li>none</li>";
13889
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml20(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>${escapeHtml20(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml20(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml20(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>${escapeHtml20(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>`;
13585
13890
  };
13586
13891
  var renderVoiceScenarioEvalHTML = (report, options = {}) => {
13587
13892
  const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
13588
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
13893
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml20(link.href)}">${escapeHtml20(link.label)}</a>`).join("")}</nav>` : "";
13589
13894
  const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
13590
- const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml19(issue)}</li>`).join("")}</ul>` : "";
13591
- const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml19(session.sessionId)}</td><td>${escapeHtml19(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml19(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
13592
- return `<section class="scenario ${scenario.status}"><h2>${escapeHtml19(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml19(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>`;
13895
+ const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml20(issue)}</li>`).join("")}</ul>` : "";
13896
+ const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml20(session.sessionId)}</td><td>${escapeHtml20(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml20(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
13897
+ return `<section class="scenario ${scenario.status}"><h2>${escapeHtml20(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml20(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>`;
13593
13898
  }).join("") : "<section><p>No scenarios configured.</p></section>";
13594
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(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>${escapeHtml19(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>`;
13899
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml20(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>${escapeHtml20(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>`;
13595
13900
  };
13596
13901
  var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
13597
13902
  const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
13598
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
13903
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml20(link.href)}">${escapeHtml20(link.label)}</a>`).join("")}</nav>` : "";
13599
13904
  const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
13600
- const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml19(scenario.label)}</td><td>${escapeHtml19(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml19([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
13601
- return `<section class="${fixture.status}"><h2>${escapeHtml19(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml19(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>`;
13905
+ const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml20(scenario.label)}</td><td>${escapeHtml20(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml20([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
13906
+ return `<section class="${fixture.status}"><h2>${escapeHtml20(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml20(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>`;
13602
13907
  }).join("") : "<section><p>No scenario fixtures configured.</p></section>";
13603
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(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>${escapeHtml19(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>`;
13908
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml20(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>${escapeHtml20(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>`;
13604
13909
  };
13605
13910
  var createVoiceEvalRoutes = (options) => {
13606
13911
  const path = options.path ?? "/evals";
13607
- const routes = new Elysia17({
13912
+ const routes = new Elysia18({
13608
13913
  name: options.name ?? "absolutejs-voice-evals"
13609
13914
  });
13610
13915
  const getReport = () => runVoiceSessionEvals({
@@ -13738,11 +14043,11 @@ var createVoiceEvalRoutes = (options) => {
13738
14043
  return routes;
13739
14044
  };
13740
14045
  // src/simulationSuite.ts
13741
- import { Elysia as Elysia20 } from "elysia";
14046
+ import { Elysia as Elysia21 } from "elysia";
13742
14047
 
13743
14048
  // src/outcomeContract.ts
13744
- import { Elysia as Elysia18 } from "elysia";
13745
- var escapeHtml20 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14049
+ import { Elysia as Elysia19 } from "elysia";
14050
+ var escapeHtml21 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13746
14051
  var getPayloadString = (event, key) => typeof event.payload[key] === "string" ? event.payload[key] : undefined;
13747
14052
  var toList = async (input) => Array.isArray(input) ? input : await input?.list() ?? [];
13748
14053
  var hydrateSessions = async (input) => {
@@ -13850,9 +14155,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
13850
14155
  const contracts = report.contracts.map((contract) => `<section class="contract ${contract.pass ? "pass" : "fail"}">
13851
14156
  <div class="contract-header">
13852
14157
  <div>
13853
- <p class="eyebrow">${escapeHtml20(contract.contractId)}</p>
13854
- <h2>${escapeHtml20(contract.label ?? contract.contractId)}</h2>
13855
- ${contract.description ? `<p>${escapeHtml20(contract.description)}</p>` : ""}
14158
+ <p class="eyebrow">${escapeHtml21(contract.contractId)}</p>
14159
+ <h2>${escapeHtml21(contract.label ?? contract.contractId)}</h2>
14160
+ ${contract.description ? `<p>${escapeHtml21(contract.description)}</p>` : ""}
13856
14161
  </div>
13857
14162
  <strong>${contract.pass ? "pass" : "fail"}</strong>
13858
14163
  </div>
@@ -13863,9 +14168,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
13863
14168
  <span>handoffs ${String(contract.matched.handoffs)}</span>
13864
14169
  <span>events ${String(contract.matched.integrationEvents)}</span>
13865
14170
  </div>
13866
- ${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml20(issue.message)}</li>`).join("")}</ul>` : ""}
14171
+ ${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml21(issue.message)}</li>`).join("")}</ul>` : ""}
13867
14172
  </section>`).join("");
13868
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml20(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>${escapeHtml20(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>`;
14173
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(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>${escapeHtml21(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>`;
13869
14174
  };
13870
14175
  var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
13871
14176
  var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
@@ -13881,7 +14186,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
13881
14186
  var createVoiceOutcomeContractRoutes = (options) => {
13882
14187
  const path = options.path ?? "/api/outcome-contracts";
13883
14188
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
13884
- const routes = new Elysia18({
14189
+ const routes = new Elysia19({
13885
14190
  name: options.name ?? "absolutejs-voice-outcome-contracts"
13886
14191
  }).get(path, createVoiceOutcomeContractJSONHandler(options));
13887
14192
  if (htmlPath) {
@@ -13891,7 +14196,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
13891
14196
  };
13892
14197
 
13893
14198
  // src/toolContract.ts
13894
- import { Elysia as Elysia19 } from "elysia";
14199
+ import { Elysia as Elysia20 } from "elysia";
13895
14200
 
13896
14201
  // src/toolRuntime.ts
13897
14202
  var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
@@ -14100,7 +14405,7 @@ var createDefaultTurn = (caseId) => ({
14100
14405
  });
14101
14406
  var defaultApi = {};
14102
14407
  var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
14103
- var escapeHtml21 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14408
+ var escapeHtml22 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14104
14409
  var evaluateExpectation = (input) => {
14105
14410
  const issues = [];
14106
14411
  const expect = input.expect;
@@ -14264,7 +14569,7 @@ var runVoiceToolContractSuite = async (options) => {
14264
14569
  };
14265
14570
  var renderVoiceToolContractHTML = (report, options = {}) => {
14266
14571
  const title = options.title ?? "Voice Tool Contracts";
14267
- const snippet = escapeHtml21(`app.use(
14572
+ const snippet = escapeHtml22(`app.use(
14268
14573
  createVoiceToolContractRoutes({
14269
14574
  htmlPath: '/tool-contracts',
14270
14575
  path: '/api/tool-contracts',
@@ -14290,19 +14595,19 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
14290
14595
  );`);
14291
14596
  const contracts = report.contracts.map((contract) => {
14292
14597
  const cases = contract.cases.map((testCase) => `<tr>
14293
- <td>${escapeHtml21(testCase.label ?? testCase.caseId)}</td>
14598
+ <td>${escapeHtml22(testCase.label ?? testCase.caseId)}</td>
14294
14599
  <td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
14295
- <td>${escapeHtml21(testCase.status)}</td>
14600
+ <td>${escapeHtml22(testCase.status)}</td>
14296
14601
  <td>${String(testCase.attempts)}</td>
14297
14602
  <td>${String(testCase.elapsedMs)}ms</td>
14298
14603
  <td>${testCase.timedOut ? "yes" : "no"}</td>
14299
- <td>${escapeHtml21(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
14604
+ <td>${escapeHtml22(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
14300
14605
  </tr>`).join("");
14301
14606
  return `<section class="contract ${contract.pass ? "pass" : "fail"}">
14302
14607
  <div class="contract-header">
14303
14608
  <div>
14304
- <p class="eyebrow">${escapeHtml21(contract.toolName)}</p>
14305
- <h2>${escapeHtml21(contract.label ?? contract.contractId)}</h2>
14609
+ <p class="eyebrow">${escapeHtml22(contract.toolName)}</p>
14610
+ <h2>${escapeHtml22(contract.label ?? contract.contractId)}</h2>
14306
14611
  </div>
14307
14612
  <strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
14308
14613
  </div>
@@ -14312,7 +14617,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
14312
14617
  </table>
14313
14618
  </section>`;
14314
14619
  }).join("");
14315
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(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>${escapeHtml21(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml21(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>`;
14620
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml22(title)}</title><style>body{background:#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>${escapeHtml22(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml22(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>`;
14316
14621
  };
14317
14622
  var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
14318
14623
  var createVoiceToolContractHTMLHandler = (options) => async () => {
@@ -14329,7 +14634,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
14329
14634
  var createVoiceToolContractRoutes = (options) => {
14330
14635
  const path = options.path ?? "/api/tool-contracts";
14331
14636
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
14332
- const routes = new Elysia19({
14637
+ const routes = new Elysia20({
14333
14638
  name: options.name ?? "absolutejs-voice-tool-contracts"
14334
14639
  }).get(path, createVoiceToolContractJSONHandler(options));
14335
14640
  if (htmlPath) {
@@ -14339,7 +14644,7 @@ var createVoiceToolContractRoutes = (options) => {
14339
14644
  };
14340
14645
 
14341
14646
  // src/simulationSuite.ts
14342
- var escapeHtml22 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14647
+ var escapeHtml23 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14343
14648
  var summarizeSection = (report) => ({
14344
14649
  failed: report.failed,
14345
14650
  passed: report.passed,
@@ -14475,15 +14780,15 @@ var renderSection = (label, summary) => {
14475
14780
  if (!summary) {
14476
14781
  return "";
14477
14782
  }
14478
- return `<article class="${escapeHtml22(summary.status)}"><span>${escapeHtml22(label)}</span><strong>${escapeHtml22(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
14783
+ return `<article class="${escapeHtml23(summary.status)}"><span>${escapeHtml23(label)}</span><strong>${escapeHtml23(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
14479
14784
  };
14480
14785
  var renderAction = (action) => {
14481
- const content = `<strong>${escapeHtml22(action.label)}</strong><p>${escapeHtml22(action.description)}</p><span>${escapeHtml22(action.section)} / ${escapeHtml22(action.severity)}</span>`;
14482
- return action.href ? `<a class="action" href="${escapeHtml22(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
14786
+ const content = `<strong>${escapeHtml23(action.label)}</strong><p>${escapeHtml23(action.description)}</p><span>${escapeHtml23(action.section)} / ${escapeHtml23(action.severity)}</span>`;
14787
+ return action.href ? `<a class="action" href="${escapeHtml23(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
14483
14788
  };
14484
14789
  var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
14485
14790
  const title = options.title ?? "Voice Simulation Suite";
14486
- const snippet = escapeHtml22(`app.use(
14791
+ const snippet = escapeHtml23(`app.use(
14487
14792
  createVoiceSimulationSuiteRoutes({
14488
14793
  htmlPath: '/voice/simulations',
14489
14794
  path: '/api/voice/simulations',
@@ -14516,12 +14821,12 @@ app.use(
14516
14821
  store: traceStore
14517
14822
  })
14518
14823
  );`);
14519
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml22(title)}</title><style>body{background:#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>${escapeHtml22(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml22(report.status)}">Status: ${escapeHtml22(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>${escapeHtml22(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
14824
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml23(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>${escapeHtml23(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml23(report.status)}">Status: ${escapeHtml23(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>${escapeHtml23(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
14520
14825
  };
14521
14826
  var createVoiceSimulationSuiteRoutes = (options) => {
14522
14827
  const path = options.path ?? "/api/voice/simulations";
14523
14828
  const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
14524
- const app = new Elysia20({
14829
+ const app = new Elysia21({
14525
14830
  name: options.name ?? "absolutejs-voice-simulation-suite"
14526
14831
  }).get(path, () => runVoiceSimulationSuite(options));
14527
14832
  if (htmlPath) {
@@ -14833,9 +15138,9 @@ var createVoiceWorkflowContractHandler = (input) => {
14833
15138
  };
14834
15139
  };
14835
15140
  // src/sessionReplay.ts
14836
- import { Elysia as Elysia21 } from "elysia";
15141
+ import { Elysia as Elysia22 } from "elysia";
14837
15142
  var getString9 = (value) => typeof value === "string" ? value : undefined;
14838
- var escapeHtml23 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
15143
+ var escapeHtml24 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14839
15144
  var increment4 = (record, key) => {
14840
15145
  record[key] = (record[key] ?? 0) + 1;
14841
15146
  };
@@ -15015,10 +15320,10 @@ var summarizeVoiceSessions = async (options = {}) => {
15015
15320
  var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
15016
15321
  '<div class="voice-sessions-list">',
15017
15322
  ...sessions.map((session) => [
15018
- `<article class="voice-session-card ${escapeHtml23(session.status)}">`,
15323
+ `<article class="voice-session-card ${escapeHtml24(session.status)}">`,
15019
15324
  '<div class="voice-session-card-header">',
15020
- `<strong>${escapeHtml23(session.sessionId)}</strong>`,
15021
- `<span>${escapeHtml23(session.status)}</span>`,
15325
+ `<strong>${escapeHtml24(session.sessionId)}</strong>`,
15326
+ `<span>${escapeHtml24(session.status)}</span>`,
15022
15327
  "</div>",
15023
15328
  "<dl>",
15024
15329
  `<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
@@ -15026,9 +15331,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
15026
15331
  `<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
15027
15332
  `<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
15028
15333
  "</dl>",
15029
- session.latestOutcome ? `<p>Outcome: ${escapeHtml23(session.latestOutcome)}</p>` : "",
15030
- session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml23).join(", ")}</p>` : "",
15031
- session.replayHref ? `<p><a href="${escapeHtml23(session.replayHref)}">Open replay</a></p>` : "",
15334
+ session.latestOutcome ? `<p>Outcome: ${escapeHtml24(session.latestOutcome)}</p>` : "",
15335
+ session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml24).join(", ")}</p>` : "",
15336
+ session.replayHref ? `<p><a href="${escapeHtml24(session.replayHref)}">Open replay</a></p>` : "",
15032
15337
  "</article>"
15033
15338
  ].join("")),
15034
15339
  "</div>"
@@ -15059,7 +15364,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
15059
15364
  var createVoiceSessionListRoutes = (options = {}) => {
15060
15365
  const path = options.path ?? "/api/voice-sessions";
15061
15366
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
15062
- const routes = new Elysia21({
15367
+ const routes = new Elysia22({
15063
15368
  name: options.name ?? "absolutejs-voice-session-list"
15064
15369
  }).get(path, createVoiceSessionsJSONHandler(options));
15065
15370
  if (htmlPath) {
@@ -15087,7 +15392,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
15087
15392
  var createVoiceSessionReplayRoutes = (options) => {
15088
15393
  const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
15089
15394
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
15090
- const routes = new Elysia21({
15395
+ const routes = new Elysia22({
15091
15396
  name: options.name ?? "absolutejs-voice-session-replay"
15092
15397
  }).get(path, createVoiceSessionReplayJSONHandler(options));
15093
15398
  if (htmlPath) {
@@ -15316,10 +15621,10 @@ var assertVoiceAgentSquadContract = async (options) => {
15316
15621
  return report;
15317
15622
  };
15318
15623
  // src/turnLatency.ts
15319
- import { Elysia as Elysia22 } from "elysia";
15624
+ import { Elysia as Elysia23 } from "elysia";
15320
15625
  var DEFAULT_WARN_AFTER_MS = 1800;
15321
15626
  var DEFAULT_FAIL_AFTER_MS = 3200;
15322
- var escapeHtml24 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
15627
+ var escapeHtml25 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
15323
15628
  var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
15324
15629
  var getString10 = (value) => typeof value === "string" && value.trim() ? value : undefined;
15325
15630
  var createTraceStageIndex = (events) => {
@@ -15451,11 +15756,11 @@ await traceStore.append({
15451
15756
  turnId,
15452
15757
  type: 'turn_latency.stage'
15453
15758
  });`;
15454
- const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml24(turn.status)}">
15455
- <header><div><p class="eyebrow">${escapeHtml24(turn.sessionId)} \xB7 ${escapeHtml24(turn.turnId)}</p><h2>${escapeHtml24(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml24(turn.status)}</strong></header>
15456
- <dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml24(stage.label)}</dt><dd>${escapeHtml24(formatMs(stage.valueMs))}</dd></div>`).join("")}</dl>
15759
+ const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml25(turn.status)}">
15760
+ <header><div><p class="eyebrow">${escapeHtml25(turn.sessionId)} \xB7 ${escapeHtml25(turn.turnId)}</p><h2>${escapeHtml25(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml25(turn.status)}</strong></header>
15761
+ <dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml25(stage.label)}</dt><dd>${escapeHtml25(formatMs(stage.valueMs))}</dd></div>`).join("")}</dl>
15457
15762
  </article>`).join("");
15458
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml24(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>${escapeHtml24(title)}</h1><div class="summary"><span class="pill ${escapeHtml24(report.status)}">${escapeHtml24(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml24(formatMs(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>${escapeHtml24(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
15763
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(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>${escapeHtml25(title)}</h1><div class="summary"><span class="pill ${escapeHtml25(report.status)}">${escapeHtml25(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml25(formatMs(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>${escapeHtml25(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
15459
15764
  };
15460
15765
  var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
15461
15766
  var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
@@ -15472,7 +15777,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
15472
15777
  var createVoiceTurnLatencyRoutes = (options) => {
15473
15778
  const path = options.path ?? "/api/turn-latency";
15474
15779
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
15475
- const routes = new Elysia22({
15780
+ const routes = new Elysia23({
15476
15781
  name: options.name ?? "absolutejs-voice-turn-latency"
15477
15782
  }).get(path, createVoiceTurnLatencyJSONHandler(options));
15478
15783
  if (htmlPath) {
@@ -15481,8 +15786,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
15481
15786
  return routes;
15482
15787
  };
15483
15788
  // src/liveLatency.ts
15484
- import { Elysia as Elysia23 } from "elysia";
15485
- var escapeHtml25 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
15789
+ import { Elysia as Elysia24 } from "elysia";
15790
+ var escapeHtml26 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
15486
15791
  var percentile = (values, percentileValue) => {
15487
15792
  if (values.length === 0) {
15488
15793
  return;
@@ -15549,13 +15854,13 @@ await traceStore.append({
15549
15854
  sessionId,
15550
15855
  type: 'client.live_latency'
15551
15856
  });`;
15552
- const rows = report.recent.map((sample) => `<tr><td>${escapeHtml25(sample.sessionId)}</td><td>${escapeHtml25(formatMs2(sample.latencyMs))}</td><td>${escapeHtml25(sample.status ?? "unknown")}</td><td>${escapeHtml25(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
15553
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(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>${escapeHtml25(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml25(report.status)}">Status: ${escapeHtml25(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml25(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml25(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml25(formatMs2(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>${escapeHtml25(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>`;
15857
+ const rows = report.recent.map((sample) => `<tr><td>${escapeHtml26(sample.sessionId)}</td><td>${escapeHtml26(formatMs2(sample.latencyMs))}</td><td>${escapeHtml26(sample.status ?? "unknown")}</td><td>${escapeHtml26(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
15858
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(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>${escapeHtml26(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml26(report.status)}">Status: ${escapeHtml26(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml26(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml26(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml26(formatMs2(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>${escapeHtml26(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>`;
15554
15859
  };
15555
15860
  var createVoiceLiveLatencyRoutes = (options) => {
15556
15861
  const path = options.path ?? "/api/live-latency";
15557
15862
  const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
15558
- const routes = new Elysia23({
15863
+ const routes = new Elysia24({
15559
15864
  name: options.name ?? "absolutejs-voice-live-latency"
15560
15865
  }).get(path, () => summarizeVoiceLiveLatency(options));
15561
15866
  if (htmlPath) {
@@ -15874,9 +16179,9 @@ None.
15874
16179
  `}`;
15875
16180
  };
15876
16181
  // src/turnQuality.ts
15877
- import { Elysia as Elysia24 } from "elysia";
16182
+ import { Elysia as Elysia25 } from "elysia";
15878
16183
  var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
15879
- var escapeHtml26 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
16184
+ var escapeHtml27 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
15880
16185
  var getTurnLatencyMs = (turn) => {
15881
16186
  const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
15882
16187
  if (firstTranscriptAt === undefined) {
@@ -15947,24 +16252,24 @@ var summarizeVoiceTurnQuality = async (options) => {
15947
16252
  };
15948
16253
  var renderVoiceTurnQualityHTML = (report, options = {}) => {
15949
16254
  const title = options.title ?? "Voice Turn Quality";
15950
- const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml26(turn.status)}">
16255
+ const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml27(turn.status)}">
15951
16256
  <div class="turn-header">
15952
16257
  <div>
15953
- <p class="eyebrow">${escapeHtml26(turn.sessionId)} \xB7 ${escapeHtml26(turn.turnId)}</p>
15954
- <h2>${escapeHtml26(turn.text || "Empty turn")}</h2>
16258
+ <p class="eyebrow">${escapeHtml27(turn.sessionId)} \xB7 ${escapeHtml27(turn.turnId)}</p>
16259
+ <h2>${escapeHtml27(turn.text || "Empty turn")}</h2>
15955
16260
  </div>
15956
- <strong>${escapeHtml26(turn.status)}</strong>
16261
+ <strong>${escapeHtml27(turn.status)}</strong>
15957
16262
  </div>
15958
16263
  <dl>
15959
- <div><dt>Source</dt><dd>${escapeHtml26(turn.source ?? "unknown")}</dd></div>
16264
+ <div><dt>Source</dt><dd>${escapeHtml27(turn.source ?? "unknown")}</dd></div>
15960
16265
  <div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
15961
- <div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml26(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
15962
- <div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml26(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
16266
+ <div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml27(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
16267
+ <div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml27(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
15963
16268
  <div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
15964
16269
  <div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
15965
16270
  </dl>
15966
16271
  </article>`).join("");
15967
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(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>${escapeHtml26(title)}</h1><div class="summary"><span class="pill ${escapeHtml26(report.status)}">${escapeHtml26(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>`;
16272
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml27(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>${escapeHtml27(title)}</h1><div class="summary"><span class="pill ${escapeHtml27(report.status)}">${escapeHtml27(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>`;
15968
16273
  };
15969
16274
  var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
15970
16275
  var createVoiceTurnQualityHTMLHandler = (options) => async () => {
@@ -15981,7 +16286,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
15981
16286
  var createVoiceTurnQualityRoutes = (options) => {
15982
16287
  const path = options.path ?? "/api/turn-quality";
15983
16288
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
15984
- const routes = new Elysia24({
16289
+ const routes = new Elysia25({
15985
16290
  name: options.name ?? "absolutejs-voice-turn-quality"
15986
16291
  }).get(path, createVoiceTurnQualityJSONHandler(options));
15987
16292
  if (htmlPath) {
@@ -15990,7 +16295,7 @@ var createVoiceTurnQualityRoutes = (options) => {
15990
16295
  return routes;
15991
16296
  };
15992
16297
  // src/telephonyOutcome.ts
15993
- import { Elysia as Elysia25 } from "elysia";
16298
+ import { Elysia as Elysia26 } from "elysia";
15994
16299
  var DEFAULT_COMPLETED_STATUSES = [
15995
16300
  "answered",
15996
16301
  "completed",
@@ -16640,7 +16945,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
16640
16945
  var createVoiceTelephonyWebhookRoutes = (options = {}) => {
16641
16946
  const path = options.path ?? "/api/voice/telephony/webhook";
16642
16947
  const handler = createVoiceTelephonyWebhookHandler(options);
16643
- return new Elysia25({
16948
+ return new Elysia26({
16644
16949
  name: options.name ?? "absolutejs-voice-telephony-webhooks"
16645
16950
  }).post(path, async ({ query, request }) => {
16646
16951
  try {
@@ -16661,11 +16966,11 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
16661
16966
  });
16662
16967
  };
16663
16968
  // src/phoneAgent.ts
16664
- import { Elysia as Elysia31 } from "elysia";
16969
+ import { Elysia as Elysia32 } from "elysia";
16665
16970
 
16666
16971
  // src/telephony/plivo.ts
16667
16972
  import { Buffer as Buffer5 } from "buffer";
16668
- import { Elysia as Elysia27 } from "elysia";
16973
+ import { Elysia as Elysia28 } from "elysia";
16669
16974
 
16670
16975
  // src/telephony/contract.ts
16671
16976
  var DEFAULT_REQUIREMENTS = [
@@ -16749,7 +17054,7 @@ var evaluateVoiceTelephonyContract = (input) => {
16749
17054
 
16750
17055
  // src/telephony/twilio.ts
16751
17056
  import { Buffer as Buffer4 } from "buffer";
16752
- import { Elysia as Elysia26 } from "elysia";
17057
+ import { Elysia as Elysia27 } from "elysia";
16753
17058
  var TWILIO_MULAW_SAMPLE_RATE = 8000;
16754
17059
  var VOICE_PCM_SAMPLE_RATE = 16000;
16755
17060
  var escapeXml2 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
@@ -16779,7 +17084,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
16779
17084
  return parameters;
16780
17085
  };
16781
17086
  var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
16782
- var escapeHtml27 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17087
+ var escapeHtml28 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16783
17088
  var getWebhookVerificationUrl = (webhook, input) => {
16784
17089
  if (!webhook?.verificationUrl) {
16785
17090
  return;
@@ -16822,23 +17127,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
16822
17127
  };
16823
17128
  var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16824
17129
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
16825
- <h1>${escapeHtml27(title)}</h1>
17130
+ <h1>${escapeHtml28(title)}</h1>
16826
17131
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
16827
17132
  <section>
16828
17133
  <h2>URLs</h2>
16829
17134
  <ul>
16830
- <li><strong>TwiML:</strong> <code>${escapeHtml27(status.urls.twiml)}</code></li>
16831
- <li><strong>Media stream:</strong> <code>${escapeHtml27(status.urls.stream)}</code></li>
16832
- <li><strong>Status webhook:</strong> <code>${escapeHtml27(status.urls.webhook)}</code></li>
17135
+ <li><strong>TwiML:</strong> <code>${escapeHtml28(status.urls.twiml)}</code></li>
17136
+ <li><strong>Media stream:</strong> <code>${escapeHtml28(status.urls.stream)}</code></li>
17137
+ <li><strong>Status webhook:</strong> <code>${escapeHtml28(status.urls.webhook)}</code></li>
16833
17138
  </ul>
16834
17139
  </section>
16835
17140
  <section>
16836
17141
  <h2>Signing</h2>
16837
17142
  <p>Mode: <code>${status.signing.mode}</code></p>
16838
- ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml27(status.signing.verificationUrl)}</code></p>` : ""}
17143
+ ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml28(status.signing.verificationUrl)}</code></p>` : ""}
16839
17144
  </section>
16840
- ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml27(name)}</code></li>`).join("")}</ul></section>` : ""}
16841
- ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml27(warning)}</li>`).join("")}</ul></section>` : ""}
17145
+ ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml28(name)}</code></li>`).join("")}</ul></section>` : ""}
17146
+ ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml28(warning)}</li>`).join("")}</ul></section>` : ""}
16842
17147
  </main>`;
16843
17148
  var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&amp;", "&");
16844
17149
  var createSmokeCheck = (name, status, message, details) => ({
@@ -16849,20 +17154,20 @@ var createSmokeCheck = (name, status, message, details) => ({
16849
17154
  });
16850
17155
  var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16851
17156
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
16852
- <h1>${escapeHtml27(title)}</h1>
17157
+ <h1>${escapeHtml28(title)}</h1>
16853
17158
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
16854
17159
  <section>
16855
17160
  <h2>Checks</h2>
16856
17161
  <ul>
16857
- ${report.checks.map((check) => `<li><strong>${escapeHtml27(check.name)}</strong>: ${escapeHtml27(check.status)}${check.message ? ` - ${escapeHtml27(check.message)}` : ""}</li>`).join("")}
17162
+ ${report.checks.map((check) => `<li><strong>${escapeHtml28(check.name)}</strong>: ${escapeHtml28(check.status)}${check.message ? ` - ${escapeHtml28(check.message)}` : ""}</li>`).join("")}
16858
17163
  </ul>
16859
17164
  </section>
16860
17165
  <section>
16861
17166
  <h2>Observed URLs</h2>
16862
17167
  <ul>
16863
- <li><strong>TwiML:</strong> <code>${escapeHtml27(report.setup.urls.twiml)}</code></li>
16864
- <li><strong>Stream:</strong> <code>${escapeHtml27(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
16865
- <li><strong>Webhook:</strong> <code>${escapeHtml27(report.setup.urls.webhook)}</code></li>
17168
+ <li><strong>TwiML:</strong> <code>${escapeHtml28(report.setup.urls.twiml)}</code></li>
17169
+ <li><strong>Stream:</strong> <code>${escapeHtml28(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
17170
+ <li><strong>Webhook:</strong> <code>${escapeHtml28(report.setup.urls.webhook)}</code></li>
16866
17171
  </ul>
16867
17172
  </section>
16868
17173
  </main>`;
@@ -17322,7 +17627,7 @@ var createTwilioVoiceRoutes = (options) => {
17322
17627
  const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
17323
17628
  const bridges = new WeakMap;
17324
17629
  const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
17325
- const app = new Elysia26({
17630
+ const app = new Elysia27({
17326
17631
  name: options.name ?? "absolutejs-voice-twilio"
17327
17632
  }).get(twimlPath, async ({ query, request }) => {
17328
17633
  const streamUrl = await resolveTwilioStreamUrl(options, {
@@ -17459,7 +17764,7 @@ var createTwilioVoiceRoutes = (options) => {
17459
17764
 
17460
17765
  // src/telephony/plivo.ts
17461
17766
  var escapeXml3 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17462
- var escapeHtml28 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17767
+ var escapeHtml29 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17463
17768
  var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
17464
17769
  var resolveRequestOrigin2 = (request) => {
17465
17770
  const url = new URL(request.url);
@@ -17710,21 +18015,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
17710
18015
  };
17711
18016
  var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
17712
18017
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
17713
- <h1>${escapeHtml28(title)}</h1>
18018
+ <h1>${escapeHtml29(title)}</h1>
17714
18019
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
17715
18020
  <ul>
17716
- <li><strong>Answer XML:</strong> <code>${escapeHtml28(status.urls.answer)}</code></li>
17717
- <li><strong>Audio stream:</strong> <code>${escapeHtml28(status.urls.stream)}</code></li>
17718
- <li><strong>Status webhook:</strong> <code>${escapeHtml28(status.urls.webhook)}</code></li>
18021
+ <li><strong>Answer XML:</strong> <code>${escapeHtml29(status.urls.answer)}</code></li>
18022
+ <li><strong>Audio stream:</strong> <code>${escapeHtml29(status.urls.stream)}</code></li>
18023
+ <li><strong>Status webhook:</strong> <code>${escapeHtml29(status.urls.webhook)}</code></li>
17719
18024
  </ul>
17720
- ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml28(name)}</code></li>`).join("")}</ul>` : ""}
17721
- ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml28(warning)}</li>`).join("")}</ul>` : ""}
18025
+ ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml29(name)}</code></li>`).join("")}</ul>` : ""}
18026
+ ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml29(warning)}</li>`).join("")}</ul>` : ""}
17722
18027
  </main>`;
17723
18028
  var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
17724
18029
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
17725
- <h1>${escapeHtml28(title)}</h1>
18030
+ <h1>${escapeHtml29(title)}</h1>
17726
18031
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
17727
- <ul>${report.checks.map((check) => `<li><strong>${escapeHtml28(check.name)}</strong>: ${escapeHtml28(check.status)}${check.message ? ` - ${escapeHtml28(check.message)}` : ""}</li>`).join("")}</ul>
18032
+ <ul>${report.checks.map((check) => `<li><strong>${escapeHtml29(check.name)}</strong>: ${escapeHtml29(check.status)}${check.message ? ` - ${escapeHtml29(check.message)}` : ""}</li>`).join("")}</ul>
17728
18033
  </main>`;
17729
18034
  var runPlivoSmokeTest = async (input) => {
17730
18035
  const setup = await buildPlivoVoiceSetupStatus(input.options, input);
@@ -17819,7 +18124,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
17819
18124
  request: input.request
17820
18125
  }) : verificationUrl ?? input.request.url
17821
18126
  }) : undefined);
17822
- const app = new Elysia27({
18127
+ const app = new Elysia28({
17823
18128
  name: options.name ?? "absolutejs-voice-plivo"
17824
18129
  }).get(answerPath, async ({ query, request }) => {
17825
18130
  const streamUrl = await resolvePlivoStreamUrl(options, {
@@ -17930,9 +18235,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
17930
18235
 
17931
18236
  // src/telephony/telnyx.ts
17932
18237
  import { Buffer as Buffer6 } from "buffer";
17933
- import { Elysia as Elysia28 } from "elysia";
18238
+ import { Elysia as Elysia29 } from "elysia";
17934
18239
  var escapeXml4 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17935
- var escapeHtml29 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
18240
+ var escapeHtml30 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17936
18241
  var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
17937
18242
  var resolveRequestOrigin3 = (request) => {
17938
18243
  const url = new URL(request.url);
@@ -18133,21 +18438,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
18133
18438
  };
18134
18439
  var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
18135
18440
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
18136
- <h1>${escapeHtml29(title)}</h1>
18441
+ <h1>${escapeHtml30(title)}</h1>
18137
18442
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
18138
18443
  <ul>
18139
- <li><strong>TeXML:</strong> <code>${escapeHtml29(status.urls.texml)}</code></li>
18140
- <li><strong>Media stream:</strong> <code>${escapeHtml29(status.urls.stream)}</code></li>
18141
- <li><strong>Status webhook:</strong> <code>${escapeHtml29(status.urls.webhook)}</code></li>
18444
+ <li><strong>TeXML:</strong> <code>${escapeHtml30(status.urls.texml)}</code></li>
18445
+ <li><strong>Media stream:</strong> <code>${escapeHtml30(status.urls.stream)}</code></li>
18446
+ <li><strong>Status webhook:</strong> <code>${escapeHtml30(status.urls.webhook)}</code></li>
18142
18447
  </ul>
18143
- ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml29(name)}</code></li>`).join("")}</ul>` : ""}
18144
- ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml29(warning)}</li>`).join("")}</ul>` : ""}
18448
+ ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml30(name)}</code></li>`).join("")}</ul>` : ""}
18449
+ ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml30(warning)}</li>`).join("")}</ul>` : ""}
18145
18450
  </main>`;
18146
18451
  var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
18147
18452
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
18148
- <h1>${escapeHtml29(title)}</h1>
18453
+ <h1>${escapeHtml30(title)}</h1>
18149
18454
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
18150
- <ul>${report.checks.map((check) => `<li><strong>${escapeHtml29(check.name)}</strong>: ${escapeHtml29(check.status)}${check.message ? ` - ${escapeHtml29(check.message)}` : ""}</li>`).join("")}</ul>
18455
+ <ul>${report.checks.map((check) => `<li><strong>${escapeHtml30(check.name)}</strong>: ${escapeHtml30(check.status)}${check.message ? ` - ${escapeHtml30(check.message)}` : ""}</li>`).join("")}</ul>
18151
18456
  </main>`;
18152
18457
  var runTelnyxSmokeTest = async (input) => {
18153
18458
  const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
@@ -18241,7 +18546,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
18241
18546
  publicKey: options.webhook?.publicKey,
18242
18547
  toleranceSeconds: options.webhook?.toleranceSeconds
18243
18548
  }) : undefined);
18244
- const app = new Elysia28({
18549
+ const app = new Elysia29({
18245
18550
  name: options.name ?? "absolutejs-voice-telnyx"
18246
18551
  }).get(texmlPath, async ({ query, request }) => {
18247
18552
  const streamUrl = await resolveTelnyxStreamUrl(options, {
@@ -18351,8 +18656,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
18351
18656
  };
18352
18657
 
18353
18658
  // src/telephony/matrix.ts
18354
- import { Elysia as Elysia29 } from "elysia";
18355
- var escapeHtml30 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
18659
+ import { Elysia as Elysia30 } from "elysia";
18660
+ var escapeHtml31 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
18356
18661
  var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
18357
18662
  var resolveEntryStatus = (contract, setup, smoke) => {
18358
18663
  if (!contract.pass || !setup.ready || smoke?.pass === false) {
@@ -18413,13 +18718,13 @@ var badgeStyles = {
18413
18718
  };
18414
18719
  var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
18415
18720
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
18416
- <h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml30(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
18721
+ <h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml31(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
18417
18722
  <p style="color:#52606d; margin: 0 0 24px;">${matrix.summary.ready}/${matrix.summary.providers} ready, ${matrix.summary.contractsPassing}/${matrix.summary.providers} contract passing, ${matrix.summary.smokePassing}/${matrix.summary.providers} smoke passing.</p>
18418
18723
  <section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
18419
18724
  ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; border-radius:18px; padding:18px; background:#fff; box-shadow:0 18px 48px rgba(15,23,42,.08);">
18420
18725
  <div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
18421
- <h2 style="margin:0; font-size:20px;">${escapeHtml30(entry.name)}</h2>
18422
- <span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml30(entry.status.toUpperCase())}</span>
18726
+ <h2 style="margin:0; font-size:20px;">${escapeHtml31(entry.name)}</h2>
18727
+ <span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml31(entry.status.toUpperCase())}</span>
18423
18728
  </div>
18424
18729
  <dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
18425
18730
  <dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
@@ -18427,15 +18732,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
18427
18732
  <dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
18428
18733
  <dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
18429
18734
  </dl>
18430
- <p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml30(entry.setup.urls.stream || "missing")}</code></p>
18431
- <p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml30(entry.setup.urls.webhook || "missing")}</code></p>
18432
- ${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml30(issue.severity)}: ${escapeHtml30(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
18735
+ <p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml31(entry.setup.urls.stream || "missing")}</code></p>
18736
+ <p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml31(entry.setup.urls.webhook || "missing")}</code></p>
18737
+ ${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml31(issue.severity)}: ${escapeHtml31(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
18433
18738
  </article>`).join("")}
18434
18739
  </section>
18435
18740
  </main>`;
18436
18741
  var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
18437
18742
  const path = options.path ?? "/api/voice/telephony/carriers";
18438
- return new Elysia29({
18743
+ return new Elysia30({
18439
18744
  name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
18440
18745
  }).get(path, async ({ query, request }) => {
18441
18746
  const providers = await options.load({ query, request });
@@ -18457,7 +18762,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
18457
18762
  };
18458
18763
 
18459
18764
  // src/phoneAgentProductionSmoke.ts
18460
- import { Elysia as Elysia30 } from "elysia";
18765
+ import { Elysia as Elysia31 } from "elysia";
18461
18766
  var defaultRequirements = [
18462
18767
  "media-started",
18463
18768
  "transcript",
@@ -18465,7 +18770,7 @@ var defaultRequirements = [
18465
18770
  "lifecycle-outcome",
18466
18771
  "no-session-error"
18467
18772
  ];
18468
- var escapeHtml31 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
18773
+ var escapeHtml32 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
18469
18774
  var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
18470
18775
  var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
18471
18776
  const value = event.payload[key];
@@ -18574,10 +18879,10 @@ var resolveHandlerOptions = async (options, input) => ({
18574
18879
  });
18575
18880
  var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
18576
18881
  const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
18577
- const issues = report.issues.map((issue) => `<li><strong>${escapeHtml31(issue.requirement)}</strong>: ${escapeHtml31(issue.message)}</li>`).join("");
18578
- const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml31(outcome)}</span>`).join("");
18579
- const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml31(requirement)}</span>`).join("");
18580
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml31(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>${escapeHtml31(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml31(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml31(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml31(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>`;
18882
+ const issues = report.issues.map((issue) => `<li><strong>${escapeHtml32(issue.requirement)}</strong>: ${escapeHtml32(issue.message)}</li>`).join("");
18883
+ const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml32(outcome)}</span>`).join("");
18884
+ const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml32(requirement)}</span>`).join("");
18885
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(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>${escapeHtml32(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml32(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml32(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml32(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>`;
18581
18886
  };
18582
18887
  var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
18583
18888
  query,
@@ -18600,7 +18905,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
18600
18905
  var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
18601
18906
  const path = options.path ?? "/api/voice/phone/smoke-contract";
18602
18907
  const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
18603
- const routes = new Elysia30({
18908
+ const routes = new Elysia31({
18604
18909
  name: options.name ?? "absolutejs-voice-phone-smoke-contract"
18605
18910
  }).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
18606
18911
  if (htmlPath) {
@@ -18643,7 +18948,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
18643
18948
  "completed",
18644
18949
  "failed"
18645
18950
  ];
18646
- var escapeHtml32 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
18951
+ var escapeHtml33 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
18647
18952
  var loadRouteJson = async (input) => {
18648
18953
  const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
18649
18954
  headers: {
@@ -18703,10 +19008,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
18703
19008
  const entry = report.matrix?.entries.find((candidate) => candidate.provider === carrier.provider && (candidate.name === carrier.name || candidate.name === (carrier.name ?? carrier.provider)));
18704
19009
  const urls = entry?.setup.urls;
18705
19010
  const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
18706
- return `<tr><td>${escapeHtml32(carrier.name ?? carrier.provider)}</td><td>${escapeHtml32(carrier.provider)}</td><td><code>${escapeHtml32(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml32(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml32(entry.status)}">${escapeHtml32(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml32(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml32(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml32(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
19011
+ return `<tr><td>${escapeHtml33(carrier.name ?? carrier.provider)}</td><td>${escapeHtml33(carrier.provider)}</td><td><code>${escapeHtml33(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml33(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml33(entry.status)}">${escapeHtml33(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml33(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml33(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml33(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
18707
19012
  }).join("");
18708
- const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml32(stage)}</code></li>`).join("");
18709
- const snippet = escapeHtml32(`const phoneAgent = createVoicePhoneAgent({
19013
+ const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml33(stage)}</code></li>`).join("");
19014
+ const snippet = escapeHtml33(`const phoneAgent = createVoicePhoneAgent({
18710
19015
  carriers: [
18711
19016
  {
18712
19017
  provider: 'twilio',
@@ -18743,10 +19048,10 @@ app.use(
18743
19048
  const urls = entry?.setup.urls;
18744
19049
  const answerLabel = carrier.provider === "telnyx" ? "TeXML URL" : carrier.provider === "plivo" ? "Answer URL" : "TwiML URL";
18745
19050
  const answerUrl = urls?.twiml;
18746
- const issueList = entry?.issues.map((issue) => `<li>${escapeHtml32(issue.severity)}: ${escapeHtml32(issue.message)}</li>`).join("") ?? "";
18747
- return `<article><h3>${escapeHtml32(carrier.name ?? carrier.provider)}</h3><ol><li>Set ${escapeHtml32(answerLabel)} to <code>${escapeHtml32(answerUrl ?? "missing")}</code>.</li><li>Set status webhook to <code>${escapeHtml32(urls?.webhook ?? "missing")}</code>.</li><li>Allow media stream URL <code>${escapeHtml32(urls?.stream ?? "missing")}</code>.</li><li>Open setup: ${carrier.setupPath ? `<a href="${escapeHtml32(carrier.setupPath)}?format=html">${escapeHtml32(carrier.setupPath)}</a>` : '<span class="muted">disabled</span>'}.</li><li>Run smoke: ${carrier.smokePath ? `<a href="${escapeHtml32(carrier.smokePath)}?format=html">${escapeHtml32(carrier.smokePath)}</a>` : '<span class="muted">disabled</span>'}.</li>${report.productionSmokePath ? `<li>Certify production smoke traces: <a href="${escapeHtml32(report.productionSmokePath.replace("/api/", "/"))}?sessionId=">${escapeHtml32(report.productionSmokePath)}</a>.</li>` : ""}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
19051
+ const issueList = entry?.issues.map((issue) => `<li>${escapeHtml33(issue.severity)}: ${escapeHtml33(issue.message)}</li>`).join("") ?? "";
19052
+ return `<article><h3>${escapeHtml33(carrier.name ?? carrier.provider)}</h3><ol><li>Set ${escapeHtml33(answerLabel)} to <code>${escapeHtml33(answerUrl ?? "missing")}</code>.</li><li>Set status webhook to <code>${escapeHtml33(urls?.webhook ?? "missing")}</code>.</li><li>Allow media stream URL <code>${escapeHtml33(urls?.stream ?? "missing")}</code>.</li><li>Open setup: ${carrier.setupPath ? `<a href="${escapeHtml33(carrier.setupPath)}?format=html">${escapeHtml33(carrier.setupPath)}</a>` : '<span class="muted">disabled</span>'}.</li><li>Run smoke: ${carrier.smokePath ? `<a href="${escapeHtml33(carrier.smokePath)}?format=html">${escapeHtml33(carrier.smokePath)}</a>` : '<span class="muted">disabled</span>'}.</li>${report.productionSmokePath ? `<li>Certify production smoke traces: <a href="${escapeHtml33(report.productionSmokePath.replace("/api/", "/"))}?sessionId=">${escapeHtml33(report.productionSmokePath)}</a>.</li>` : ""}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
18748
19053
  }).join("");
18749
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(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>${escapeHtml32(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="${escapeHtml32(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>`;
19054
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml33(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>${escapeHtml33(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="${escapeHtml33(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>`;
18750
19055
  };
18751
19056
  var createVoicePhoneAgent = (options) => {
18752
19057
  const carrierSummaries = options.carriers.map((carrier) => ({
@@ -18755,7 +19060,7 @@ var createVoicePhoneAgent = (options) => {
18755
19060
  setupPath: resolveSetupPath(carrier),
18756
19061
  smokePath: resolveSmokePath(carrier)
18757
19062
  }));
18758
- const app = new Elysia31({
19063
+ const app = new Elysia32({
18759
19064
  name: options.name ?? "absolutejs-voice-phone-agent"
18760
19065
  });
18761
19066
  for (const carrier of options.carriers) {
@@ -20809,8 +21114,8 @@ var createOpenAIVoiceTTS = (options) => {
20809
21114
  };
20810
21115
  };
20811
21116
  // src/providerCapabilities.ts
20812
- import { Elysia as Elysia32 } from "elysia";
20813
- var escapeHtml33 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21117
+ import { Elysia as Elysia33 } from "elysia";
21118
+ var escapeHtml34 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20814
21119
  var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
20815
21120
  configured: true,
20816
21121
  features: options.features?.[provider],
@@ -20873,27 +21178,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
20873
21178
  var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
20874
21179
  const title = options.title ?? "Voice Provider Capabilities";
20875
21180
  const cards = report.capabilities.map((capability) => {
20876
- const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml33(feature)}</span>`).join("");
20877
- return `<article class="card ${escapeHtml33(capability.status)}">
21181
+ const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml34(feature)}</span>`).join("");
21182
+ return `<article class="card ${escapeHtml34(capability.status)}">
20878
21183
  <div class="card-header">
20879
21184
  <div>
20880
- <p class="eyebrow">${escapeHtml33(capability.kind)}</p>
20881
- <h2>${escapeHtml33(capability.label ?? capability.provider)}</h2>
21185
+ <p class="eyebrow">${escapeHtml34(capability.kind)}</p>
21186
+ <h2>${escapeHtml34(capability.label ?? capability.provider)}</h2>
20882
21187
  </div>
20883
- <strong>${escapeHtml33(capability.status)}</strong>
21188
+ <strong>${escapeHtml34(capability.status)}</strong>
20884
21189
  </div>
20885
- ${capability.description ? `<p>${escapeHtml33(capability.description)}</p>` : ""}
21190
+ ${capability.description ? `<p>${escapeHtml34(capability.description)}</p>` : ""}
20886
21191
  <dl>
20887
21192
  <div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
20888
21193
  <div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
20889
- <div><dt>Model</dt><dd>${escapeHtml33(capability.model ?? "default")}</dd></div>
21194
+ <div><dt>Model</dt><dd>${escapeHtml34(capability.model ?? "default")}</dd></div>
20890
21195
  <div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
20891
21196
  <div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
20892
21197
  </dl>
20893
21198
  ${features ? `<div class="features">${features}</div>` : ""}
20894
21199
  </article>`;
20895
21200
  }).join("");
20896
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml33(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>${escapeHtml33(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>`;
21201
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml34(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>${escapeHtml34(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>`;
20897
21202
  };
20898
21203
  var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
20899
21204
  var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
@@ -20910,7 +21215,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
20910
21215
  var createVoiceProviderCapabilityRoutes = (options) => {
20911
21216
  const path = options.path ?? "/api/provider-capabilities";
20912
21217
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
20913
- const routes = new Elysia32({
21218
+ const routes = new Elysia33({
20914
21219
  name: options.name ?? "absolutejs-voice-provider-capabilities"
20915
21220
  }).get(path, createVoiceProviderCapabilityJSONHandler(options));
20916
21221
  if (htmlPath) {
@@ -20919,8 +21224,8 @@ var createVoiceProviderCapabilityRoutes = (options) => {
20919
21224
  return routes;
20920
21225
  };
20921
21226
  // src/resilienceRoutes.ts
20922
- import { Elysia as Elysia33 } from "elysia";
20923
- var escapeHtml34 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21227
+ import { Elysia as Elysia34 } from "elysia";
21228
+ var escapeHtml35 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20924
21229
  var getString12 = (value) => typeof value === "string" ? value : undefined;
20925
21230
  var getNumber7 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
20926
21231
  var getBoolean2 = (value) => value === true;
@@ -21067,13 +21372,13 @@ var summarizeRoutingEvents = (events) => {
21067
21372
  };
21068
21373
  var renderProviderCards = (title, providers) => {
21069
21374
  if (providers.length === 0) {
21070
- return `<p class="muted">No ${escapeHtml34(title)} provider health yet.</p>`;
21375
+ return `<p class="muted">No ${escapeHtml35(title)} provider health yet.</p>`;
21071
21376
  }
21072
21377
  return `<div class="provider-grid">${providers.map((provider) => `
21073
- <article class="card provider ${escapeHtml34(provider.status)}">
21378
+ <article class="card provider ${escapeHtml35(provider.status)}">
21074
21379
  <div class="card-header">
21075
- <strong>${escapeHtml34(provider.provider)}</strong>
21076
- <span>${escapeHtml34(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
21380
+ <strong>${escapeHtml35(provider.provider)}</strong>
21381
+ <span>${escapeHtml35(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
21077
21382
  </div>
21078
21383
  <dl>
21079
21384
  <div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
@@ -21082,7 +21387,7 @@ var renderProviderCards = (title, providers) => {
21082
21387
  <div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
21083
21388
  <div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
21084
21389
  </dl>
21085
- ${provider.lastError ? `<p class="muted">${escapeHtml34(provider.lastError)}</p>` : ""}
21390
+ ${provider.lastError ? `<p class="muted">${escapeHtml35(provider.lastError)}</p>` : ""}
21086
21391
  </article>
21087
21392
  `).join("")}</div>`;
21088
21393
  };
@@ -21091,24 +21396,24 @@ var renderTimeline2 = (events) => {
21091
21396
  return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
21092
21397
  }
21093
21398
  return `<div class="timeline">${events.slice(0, 40).map((event) => `
21094
- <article class="card event ${escapeHtml34(event.status ?? "unknown")}">
21399
+ <article class="card event ${escapeHtml35(event.status ?? "unknown")}">
21095
21400
  <div class="card-header">
21096
- <strong>${escapeHtml34(event.kind.toUpperCase())} ${escapeHtml34(event.operation ?? "generate")}</strong>
21401
+ <strong>${escapeHtml35(event.kind.toUpperCase())} ${escapeHtml35(event.operation ?? "generate")}</strong>
21097
21402
  <span>${new Date(event.at).toLocaleString()}</span>
21098
21403
  </div>
21099
21404
  <p>
21100
- <span class="pill">${escapeHtml34(event.status ?? "unknown")}</span>
21101
- <span class="pill">provider: ${escapeHtml34(event.provider ?? "unknown")}</span>
21102
- ${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml34(event.fallbackProvider)}</span>` : ""}
21405
+ <span class="pill">${escapeHtml35(event.status ?? "unknown")}</span>
21406
+ <span class="pill">provider: ${escapeHtml35(event.provider ?? "unknown")}</span>
21407
+ ${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml35(event.fallbackProvider)}</span>` : ""}
21103
21408
  ${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
21104
21409
  </p>
21105
21410
  <dl>
21106
21411
  <div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
21107
21412
  <div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
21108
21413
  <div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
21109
- <div><dt>Session</dt><dd>${escapeHtml34(event.sessionId)}</dd></div>
21414
+ <div><dt>Session</dt><dd>${escapeHtml35(event.sessionId)}</dd></div>
21110
21415
  </dl>
21111
- ${event.error ? `<p class="muted">${escapeHtml34(event.error)}</p>` : ""}
21416
+ ${event.error ? `<p class="muted">${escapeHtml35(event.error)}</p>` : ""}
21112
21417
  </article>
21113
21418
  `).join("")}</div>`;
21114
21419
  };
@@ -21118,9 +21423,9 @@ var renderSessionKind = (kind, summary) => {
21118
21423
  const status = latest?.status ?? "idle";
21119
21424
  const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
21120
21425
  return `<div>
21121
- <dt>${escapeHtml34(kind.toUpperCase())}</dt>
21122
- <dd>${escapeHtml34(provider)}${escapeHtml34(fallback)}</dd>
21123
- <small>${escapeHtml34(status)} \xB7 ${summary.runCount} event${summary.runCount === 1 ? "" : "s"} \xB7 ${summary.errorCount} error${summary.errorCount === 1 ? "" : "s"} \xB7 ${summary.fallbackCount} fallback${summary.fallbackCount === 1 ? "" : "s"}</small>
21426
+ <dt>${escapeHtml35(kind.toUpperCase())}</dt>
21427
+ <dd>${escapeHtml35(provider)}${escapeHtml35(fallback)}</dd>
21428
+ <small>${escapeHtml35(status)} \xB7 ${summary.runCount} event${summary.runCount === 1 ? "" : "s"} \xB7 ${summary.errorCount} error${summary.errorCount === 1 ? "" : "s"} \xB7 ${summary.fallbackCount} fallback${summary.fallbackCount === 1 ? "" : "s"}</small>
21124
21429
  </div>`;
21125
21430
  };
21126
21431
  var renderSessionSummaries = (sessions) => {
@@ -21128,10 +21433,10 @@ var renderSessionSummaries = (sessions) => {
21128
21433
  return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
21129
21434
  }
21130
21435
  return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
21131
- <article class="card session ${escapeHtml34(session.status)}">
21436
+ <article class="card session ${escapeHtml35(session.status)}">
21132
21437
  <div class="card-header">
21133
- <strong>${escapeHtml34(session.sessionId)}</strong>
21134
- <span>${escapeHtml34(session.status)}</span>
21438
+ <strong>${escapeHtml35(session.sessionId)}</strong>
21439
+ <span>${escapeHtml35(session.status)}</span>
21135
21440
  </div>
21136
21441
  <p>
21137
21442
  <span class="pill">${session.eventCount} routing events</span>
@@ -21158,21 +21463,21 @@ var renderSimulationControls = (kind, simulation) => {
21158
21463
  const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
21159
21464
  const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
21160
21465
  const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
21161
- return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml34(pathPrefix)}">
21162
- <p class="muted">${escapeHtml34(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
21466
+ return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml35(pathPrefix)}">
21467
+ <p class="muted">${escapeHtml35(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
21163
21468
  <div class="simulate-actions">
21164
- ${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml34(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml34(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
21165
- ${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml34(provider.provider)}">Mark ${escapeHtml34(provider.provider)} recovered</button>`).join("")}
21469
+ ${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml35(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml35(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
21470
+ ${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml35(provider.provider)}">Mark ${escapeHtml35(provider.provider)} recovered</button>`).join("")}
21166
21471
  </div>
21167
- ${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml34(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
21472
+ ${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml35(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
21168
21473
  <pre class="simulate-output" hidden></pre>
21169
21474
  </div>`;
21170
21475
  };
21171
21476
  var renderVoiceResilienceHTML = (input) => {
21172
21477
  const summary = summarizeRoutingEvents(input.routingEvents);
21173
- const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml34(kind)}: ${String(count)}</span>`).join("");
21174
- const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml34(link.href)}">${escapeHtml34(link.label)}</a>`).join(" \xB7 ") : "";
21175
- const snippet = escapeHtml34(`const sttSimulator = createVoiceIOProviderFailureSimulator({
21478
+ const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml35(kind)}: ${String(count)}</span>`).join("");
21479
+ const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml35(link.href)}">${escapeHtml35(link.label)}</a>`).join(" \xB7 ") : "";
21480
+ const snippet = escapeHtml35(`const sttSimulator = createVoiceIOProviderFailureSimulator({
21176
21481
  kind: 'stt',
21177
21482
  providers: ['deepgram', 'assemblyai'],
21178
21483
  fallback: ['deepgram', 'assemblyai'],
@@ -21210,7 +21515,7 @@ app.use(
21210
21515
  <head>
21211
21516
  <meta charset="utf-8" />
21212
21517
  <meta name="viewport" content="width=device-width, initial-scale=1" />
21213
- <title>${escapeHtml34(input.title ?? "AbsoluteJS Voice Resilience")}</title>
21518
+ <title>${escapeHtml35(input.title ?? "AbsoluteJS Voice Resilience")}</title>
21214
21519
  <style>
21215
21520
  :root { color-scheme: dark; }
21216
21521
  body { background: radial-gradient(circle at top left, #172554, #09090b 36%, #050505); color: #f4f4f5; font-family: ui-sans-serif, system-ui, sans-serif; margin: 0; padding: 24px; }
@@ -21362,7 +21667,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
21362
21667
  };
21363
21668
  var createVoiceResilienceRoutes = (options) => {
21364
21669
  const path = options.path ?? "/resilience";
21365
- const routes = new Elysia33({
21670
+ const routes = new Elysia34({
21366
21671
  name: options.name ?? "absolutejs-voice-resilience"
21367
21672
  }).get(path, async () => {
21368
21673
  const events = await options.store.list();
@@ -21440,8 +21745,8 @@ var assertVoiceProviderRoutingContract = async (options) => {
21440
21745
  return report;
21441
21746
  };
21442
21747
  // src/productionReadiness.ts
21443
- import { Elysia as Elysia34 } from "elysia";
21444
- var escapeHtml35 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21748
+ import { Elysia as Elysia35 } from "elysia";
21749
+ var escapeHtml36 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21445
21750
  var rollupStatus2 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
21446
21751
  var readinessGateCodes = {
21447
21752
  "Agent squad contracts": "voice.readiness.agent_squad_contracts",
@@ -22392,22 +22697,22 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
22392
22697
  var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
22393
22698
  var renderVoiceProductionReadinessHTML = (report, options = {}) => {
22394
22699
  const title = options.title ?? "AbsoluteJS Voice Production Readiness";
22395
- const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml35(report.profile.name)}</h2><p>${escapeHtml35(report.profile.description)}</p><p>${escapeHtml35(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="${escapeHtml35(surface.href)}">${escapeHtml35(surface.label)}</a>` : escapeHtml35(surface.label)}</strong></article>`).join("")}</div></section>` : "";
22700
+ const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml36(report.profile.name)}</h2><p>${escapeHtml36(report.profile.description)}</p><p>${escapeHtml36(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="${escapeHtml36(surface.href)}">${escapeHtml36(surface.label)}</a>` : escapeHtml36(surface.label)}</strong></article>`).join("")}</div></section>` : "";
22396
22701
  const checks = report.checks.map((check, index) => {
22397
- const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml35(action.href)}">${escapeHtml35(action.label)}</button>` : `<a href="${escapeHtml35(action.href)}">${escapeHtml35(action.label)}</a>`).join("");
22398
- return `<article class="check ${escapeHtml35(check.status)}">
22702
+ const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml36(action.href)}">${escapeHtml36(action.label)}</button>` : `<a href="${escapeHtml36(action.href)}">${escapeHtml36(action.label)}</a>`).join("");
22703
+ return `<article class="check ${escapeHtml36(check.status)}">
22399
22704
  <div>
22400
- <span>${escapeHtml35(check.status.toUpperCase())}</span>
22401
- <h2>${escapeHtml35(check.label)}</h2>
22402
- ${check.detail ? `<p>${escapeHtml35(check.detail)}</p>` : ""}
22403
- ${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml35(check.proofSource.href)}">${escapeHtml35(check.proofSource.sourceLabel)}</a>` : escapeHtml35(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml35(check.proofSource.detail)}` : ""}</p>` : ""}
22705
+ <span>${escapeHtml36(check.status.toUpperCase())}</span>
22706
+ <h2>${escapeHtml36(check.label)}</h2>
22707
+ ${check.detail ? `<p>${escapeHtml36(check.detail)}</p>` : ""}
22708
+ ${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml36(check.proofSource.href)}">${escapeHtml36(check.proofSource.sourceLabel)}</a>` : escapeHtml36(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml36(check.proofSource.detail)}` : ""}</p>` : ""}
22404
22709
  ${actions ? `<p class="actions">${actions}</p>` : ""}
22405
22710
  </div>
22406
- <strong>${escapeHtml35(String(check.value ?? check.status))}</strong>
22407
- ${check.href ? `<a href="${escapeHtml35(check.href)}">Open surface</a>` : ""}
22711
+ <strong>${escapeHtml36(String(check.value ?? check.status))}</strong>
22712
+ ${check.href ? `<a href="${escapeHtml36(check.href)}">Open surface</a>` : ""}
22408
22713
  </article>`;
22409
22714
  }).join("");
22410
- const snippet = escapeHtml35(`createVoiceProductionReadinessRoutes({
22715
+ const snippet = escapeHtml36(`createVoiceProductionReadinessRoutes({
22411
22716
  htmlPath: '/production-readiness',
22412
22717
  path: '/api/production-readiness',
22413
22718
  gatePath: '/api/production-readiness/gate',
@@ -22423,13 +22728,13 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
22423
22728
  providerRoutingContracts: loadProviderRoutingContracts,
22424
22729
  store: traceStore
22425
22730
  });`);
22426
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml35(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 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>${escapeHtml35(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 ${escapeHtml35(report.status)}">Overall: ${escapeHtml35(report.status.toUpperCase())}</p><p>Checked ${escapeHtml35(new Date(report.checkedAt).toLocaleString())}</p></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>`;
22731
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(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 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>${escapeHtml36(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 ${escapeHtml36(report.status)}">Overall: ${escapeHtml36(report.status.toUpperCase())}</p><p>Checked ${escapeHtml36(new Date(report.checkedAt).toLocaleString())}</p></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>`;
22427
22732
  };
22428
22733
  var createVoiceProductionReadinessRoutes = (options) => {
22429
22734
  const path = options.path ?? "/api/production-readiness";
22430
22735
  const gatePath = options.gatePath === undefined ? "/api/production-readiness/gate" : options.gatePath;
22431
22736
  const htmlPath = options.htmlPath ?? "/production-readiness";
22432
- const routes = new Elysia34({
22737
+ const routes = new Elysia35({
22433
22738
  name: options.name ?? "absolutejs-voice-production-readiness"
22434
22739
  });
22435
22740
  routes.get(path, async ({ query, request }) => buildVoiceProductionReadinessReport(options, { query, request }));
@@ -22793,8 +23098,8 @@ var recommendVoiceReadinessProfile = (options) => {
22793
23098
  };
22794
23099
  };
22795
23100
  // src/providerStackRecommendations.ts
22796
- import { Elysia as Elysia35 } from "elysia";
22797
- var escapeHtml36 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
23101
+ import { Elysia as Elysia36 } from "elysia";
23102
+ var escapeHtml37 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
22798
23103
  var profileProviderPriorities = {
22799
23104
  "meeting-recorder": {
22800
23105
  llm: ["openai", "anthropic", "gemini"],
@@ -23037,17 +23342,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
23037
23342
  var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
23038
23343
  const title = options.title ?? "Voice Provider Contract Matrix";
23039
23344
  const rows = report.rows.map((row) => {
23040
- const checks = row.checks.map((check) => `<li class="${escapeHtml36(check.status)}"><strong>${escapeHtml36(check.label)}</strong><span>${escapeHtml36(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml36(check.remediation.href)}">${escapeHtml36(check.remediation.label)}</a>` : escapeHtml36(check.remediation.label)}: ${escapeHtml36(check.remediation.detail)}</em>` : ""}</li>`).join("");
23041
- return `<article class="row ${escapeHtml36(row.status)}">
23345
+ const checks = row.checks.map((check) => `<li class="${escapeHtml37(check.status)}"><strong>${escapeHtml37(check.label)}</strong><span>${escapeHtml37(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml37(check.remediation.href)}">${escapeHtml37(check.remediation.label)}</a>` : escapeHtml37(check.remediation.label)}: ${escapeHtml37(check.remediation.detail)}</em>` : ""}</li>`).join("");
23346
+ return `<article class="row ${escapeHtml37(row.status)}">
23042
23347
  <div>
23043
- <p class="eyebrow">${escapeHtml36(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
23044
- <h2>${escapeHtml36(row.provider)}</h2>
23045
- <p class="status ${escapeHtml36(row.status)}">${escapeHtml36(row.status.toUpperCase())}</p>
23348
+ <p class="eyebrow">${escapeHtml37(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
23349
+ <h2>${escapeHtml37(row.provider)}</h2>
23350
+ <p class="status ${escapeHtml37(row.status)}">${escapeHtml37(row.status.toUpperCase())}</p>
23046
23351
  </div>
23047
23352
  <ul>${checks}</ul>
23048
23353
  </article>`;
23049
23354
  }).join("");
23050
- const snippet = escapeHtml36(`const providerContracts = () =>
23355
+ const snippet = escapeHtml37(`const providerContracts = () =>
23051
23356
  createVoiceProviderContractMatrixPreset('phone-agent', {
23052
23357
  env: process.env,
23053
23358
  providers: {
@@ -23068,7 +23373,7 @@ createVoiceProductionReadinessRoutes({
23068
23373
  providerContractMatrix: () =>
23069
23374
  buildVoiceProviderContractMatrix(providerContracts())
23070
23375
  });`);
23071
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(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>${escapeHtml36(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>`;
23376
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml37(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>${escapeHtml37(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>`;
23072
23377
  };
23073
23378
  var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
23074
23379
  var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
@@ -23083,7 +23388,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
23083
23388
  var createVoiceProviderContractMatrixRoutes = (options) => {
23084
23389
  const path = options.path ?? "/api/provider-contracts";
23085
23390
  const htmlPath = options.htmlPath ?? "/provider-contracts";
23086
- const routes = new Elysia35({
23391
+ const routes = new Elysia36({
23087
23392
  name: options.name ?? "absolutejs-voice-provider-contract-matrix"
23088
23393
  });
23089
23394
  const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
@@ -23142,7 +23447,7 @@ var evaluateVoiceProviderStackGaps = (input) => {
23142
23447
  };
23143
23448
  };
23144
23449
  // src/opsConsoleRoutes.ts
23145
- import { Elysia as Elysia36 } from "elysia";
23450
+ import { Elysia as Elysia37 } from "elysia";
23146
23451
  var DEFAULT_LINKS = [
23147
23452
  {
23148
23453
  description: "Quality gates for CI, deploy checks, and production readiness.",
@@ -23177,7 +23482,7 @@ var DEFAULT_LINKS = [
23177
23482
  label: "Handoffs"
23178
23483
  }
23179
23484
  ];
23180
- var escapeHtml37 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
23485
+ var escapeHtml38 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
23181
23486
  var countProviderStatuses = (providers) => {
23182
23487
  const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
23183
23488
  const healthy = providers.filter((provider) => provider.status === "healthy").length;
@@ -23246,20 +23551,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
23246
23551
  trace
23247
23552
  };
23248
23553
  };
23249
- var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml37(input.label)}</span><strong>${escapeHtml37(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml37(input.status)}">${escapeHtml37(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml37(input.href)}">Open</a>` : ""}</article>`;
23554
+ var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml38(input.label)}</span><strong>${escapeHtml38(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml38(input.status)}">${escapeHtml38(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml38(input.href)}">Open</a>` : ""}</article>`;
23250
23555
  var renderVoiceOpsConsoleHTML = (report, options = {}) => {
23251
23556
  const links = report.links.map((link) => `<article class="surface">
23252
- <div><h2>${escapeHtml37(link.label)}</h2>${link.description ? `<p>${escapeHtml37(link.description)}</p>` : ""}</div>
23253
- <p><a href="${escapeHtml37(link.href)}">Open ${escapeHtml37(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml37(link.statusHref)}">Status</a>` : ""}</p>
23557
+ <div><h2>${escapeHtml38(link.label)}</h2>${link.description ? `<p>${escapeHtml38(link.description)}</p>` : ""}</div>
23558
+ <p><a href="${escapeHtml38(link.href)}">Open ${escapeHtml38(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml38(link.statusHref)}">Status</a>` : ""}</p>
23254
23559
  </article>`).join("");
23255
- const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml37(session.sessionId)}</td><td>${escapeHtml37(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml37(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
23256
- const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml37(event.kind)}</td><td>${escapeHtml37(event.provider ?? "unknown")}</td><td>${escapeHtml37(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml37(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
23560
+ const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml38(session.sessionId)}</td><td>${escapeHtml38(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml38(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
23561
+ const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml38(event.kind)}</td><td>${escapeHtml38(event.provider ?? "unknown")}</td><td>${escapeHtml38(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml38(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
23257
23562
  const title = options.title ?? "AbsoluteJS Voice Ops Console";
23258
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml37(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>${escapeHtml37(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 ${escapeHtml37(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>`;
23563
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(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>${escapeHtml38(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 ${escapeHtml38(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>`;
23259
23564
  };
23260
23565
  var createVoiceOpsConsoleRoutes = (options) => {
23261
23566
  const path = options.path ?? "/ops-console";
23262
- const routes = new Elysia36({
23567
+ const routes = new Elysia37({
23263
23568
  name: options.name ?? "absolutejs-voice-ops-console"
23264
23569
  });
23265
23570
  const getReport = () => buildVoiceOpsConsoleReport(options);
@@ -23276,11 +23581,11 @@ var createVoiceOpsConsoleRoutes = (options) => {
23276
23581
  return routes;
23277
23582
  };
23278
23583
  // src/operationsRecord.ts
23279
- import { Elysia as Elysia38 } from "elysia";
23584
+ import { Elysia as Elysia39 } from "elysia";
23280
23585
 
23281
23586
  // src/traceTimeline.ts
23282
- import { Elysia as Elysia37 } from "elysia";
23283
- var escapeHtml38 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
23587
+ import { Elysia as Elysia38 } from "elysia";
23588
+ var escapeHtml39 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
23284
23589
  var getString14 = (value) => typeof value === "string" && value.trim() ? value : undefined;
23285
23590
  var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
23286
23591
  var firstString3 = (payload, keys) => {
@@ -23448,16 +23753,16 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
23448
23753
  };
23449
23754
  };
23450
23755
  var formatMs3 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
23451
- var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${escapeHtml38(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs3(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs3(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
23756
+ var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${escapeHtml39(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs3(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs3(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
23452
23757
  var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
23453
- const events = session.events.map((event) => `<tr class="${escapeHtml38(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml38(event.type)}</td><td>${escapeHtml38(event.label)}</td><td>${escapeHtml38(event.provider ?? "")}</td><td>${escapeHtml38(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
23454
- const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml38(issue.severity)}">${escapeHtml38(issue.code)}: ${escapeHtml38(issue.message)}</li>`).join("") : "<li>none</li>";
23455
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(options.title ?? "Voice Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml38(session.sessionId)}</h1><p class="status ${escapeHtml38(session.status)}">${escapeHtml38(session.status)}</p></header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs3(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards2(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
23758
+ const events = session.events.map((event) => `<tr class="${escapeHtml39(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml39(event.type)}</td><td>${escapeHtml39(event.label)}</td><td>${escapeHtml39(event.provider ?? "")}</td><td>${escapeHtml39(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
23759
+ const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml39(issue.severity)}">${escapeHtml39(issue.code)}: ${escapeHtml39(issue.message)}</li>`).join("") : "<li>none</li>";
23760
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml39(session.sessionId)}</h1><p class="status ${escapeHtml39(session.status)}">${escapeHtml39(session.status)}</p></header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs3(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards2(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
23456
23761
  };
23457
- var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml38(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml38(session.sessionId)}</a></td><td>${escapeHtml38(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs3(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml38(provider.provider)).join(", ")}</td></tr>`).join("");
23762
+ var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml39(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml39(session.sessionId)}</a></td><td>${escapeHtml39(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs3(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml39(provider.provider)).join(", ")}</td></tr>`).join("");
23458
23763
  var timelineCSS = "body{background:#0f1318;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}a{color:#fbbf24}.eyebrow{color:#fbbf24;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.5rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.metrics,.providers{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:20px 0}.metrics article,.providers article{background:#181f27;border:1px solid #2b3642;border-radius:20px;padding:16px}.metrics span,dt,.muted{color:#a8b0b8}.metrics strong{display:block;font-size:2rem}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:12px 0 0}dd{font-weight:800;margin:4px 0 0}table{background:#181f27;border-collapse:collapse;border-radius:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #2b3642;padding:12px;text-align:left}section{margin-top:28px}@media(max-width:760px){main{padding:20px}table{font-size:.9rem}}";
23459
23764
  var renderVoiceTraceTimelineHTML = (report, options = {}) => {
23460
- const snippet = escapeHtml38(`const traceStore = createVoiceTraceSinkStore({
23765
+ const snippet = escapeHtml39(`const traceStore = createVoiceTraceSinkStore({
23461
23766
  store: runtimeStorage.traces,
23462
23767
  sinks: [
23463
23768
  createVoiceTraceHTTPSink({
@@ -23483,13 +23788,13 @@ app.use(
23483
23788
  traceDeliveries: runtimeStorage.traceDeliveries
23484
23789
  })
23485
23790
  );`);
23486
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}.primitive{background:#181f27;border:1px solid #334155;border-radius:20px;margin:20px 0;padding:18px}.primitive p{line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #2b3642;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.primitive code{color:#bfdbfe}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml38(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTraceTimelineRoutes(...)</code> makes traces the proof backbone</h2><p class="muted">Mount trace timelines from the same trace store used by readiness, simulations, provider recovery, delivery sinks, and phone-agent smoke proof.</p><pre><code>${snippet}</code></pre></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
23791
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}.primitive{background:#181f27;border:1px solid #334155;border-radius:20px;margin:20px 0;padding:18px}.primitive p{line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #2b3642;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.primitive code{color:#bfdbfe}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml39(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTraceTimelineRoutes(...)</code> makes traces the proof backbone</h2><p class="muted">Mount trace timelines from the same trace store used by readiness, simulations, provider recovery, delivery sinks, and phone-agent smoke proof.</p><pre><code>${snippet}</code></pre></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
23487
23792
  };
23488
23793
  var createVoiceTraceTimelineRoutes = (options) => {
23489
23794
  const path = options.path ?? "/api/voice-traces";
23490
23795
  const htmlPath = options.htmlPath ?? "/traces";
23491
23796
  const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
23492
- const routes = new Elysia37({
23797
+ const routes = new Elysia38({
23493
23798
  name: options.name ?? "absolutejs-voice-trace-timelines"
23494
23799
  });
23495
23800
  const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
@@ -23643,16 +23948,16 @@ var buildVoiceOperationsRecord = async (options) => {
23643
23948
  traceEvents
23644
23949
  };
23645
23950
  };
23646
- var escapeHtml39 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
23951
+ var escapeHtml40 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
23647
23952
  var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
23648
23953
  var renderVoiceOperationsRecordHTML = (record, options = {}) => {
23649
- const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml39(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs4(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
23650
- const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml39(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml39(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml39(handoff.status ?? "")}</span><p>${escapeHtml39(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
23651
- const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml39(tool.toolName ?? "tool")}</strong> <span>${escapeHtml39(tool.status ?? "")}</span> ${formatMs4(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml39(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
23652
- const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml39(review.title)}</strong> <span>${escapeHtml39(review.summary.outcome ?? "")}</span><p>${escapeHtml39(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
23653
- const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml39(task.title)}</strong> <span>${escapeHtml39(task.status)}</span><p>${escapeHtml39(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
23654
- const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml39(event.type)}</strong> <span>${escapeHtml39(event.deliveryStatus ?? "local")}</span><p>${escapeHtml39(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
23655
- const snippet = escapeHtml39(`app.use(
23954
+ const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml40(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs4(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
23955
+ const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml40(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml40(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml40(handoff.status ?? "")}</span><p>${escapeHtml40(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
23956
+ const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml40(tool.toolName ?? "tool")}</strong> <span>${escapeHtml40(tool.status ?? "")}</span> ${formatMs4(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml40(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
23957
+ const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml40(review.title)}</strong> <span>${escapeHtml40(review.summary.outcome ?? "")}</span><p>${escapeHtml40(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
23958
+ const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml40(task.title)}</strong> <span>${escapeHtml40(task.status)}</span><p>${escapeHtml40(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
23959
+ const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml40(event.type)}</strong> <span>${escapeHtml40(event.deliveryStatus ?? "local")}</span><p>${escapeHtml40(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
23960
+ const snippet = escapeHtml40(`app.use(
23656
23961
  createVoiceOperationsRecordRoutes({
23657
23962
  audit: auditStore,
23658
23963
  integrationEvents: opsEvents,
@@ -23666,12 +23971,12 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
23666
23971
  tasks: opsTasks
23667
23972
  })
23668
23973
  );`);
23669
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Operations Record")}</title><style>body{background:#101417;color:#f9f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.eyebrow{color:#fbbf24;font-size:.8rem;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 #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.card,.primitive{background:#182025;border:1px solid #2d3a43;border-radius:20px;padding:16px}.card span,.muted{color:#a9b4bd}.card strong{display:block;font-size:2rem}section{margin-top:28px}article{display:grid;gap:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#182025;border:1px solid #2d3a43;border-radius:16px;padding:14px}pre{background:#080d10;border:1px solid #2d3a43;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}</style></head><body><main><p class="eyebrow">Portable production proof</p><h1>${escapeHtml39(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml39(record.status)}">${escapeHtml39(record.status)}</p><section class="grid"><div class="card"><span>Events</span><strong>${String(record.summary.eventCount)}</strong></div><div class="card"><span>Turns</span><strong>${String(record.summary.turnCount)}</strong></div><div class="card"><span>Errors</span><strong>${String(record.summary.errorCount)}</strong></div><div class="card"><span>Duration</span><strong>${formatMs4(record.summary.callDurationMs)}</strong></div><div class="card"><span>Audit</span><strong>${String(record.audit?.total ?? 0)}</strong></div><div class="card"><span>Reviews</span><strong>${String(record.reviews?.total ?? 0)}</strong></div><div class="card"><span>Tasks</span><strong>${String(record.tasks?.total ?? 0)}</strong></div><div class="card"><span>Integrations</span><strong>${String(record.integrationEvents?.total ?? 0)}</strong></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceOperationsRecordRoutes(...)</code> gives every call one debuggable object</h2><p class="muted">Use this as the support/debug payload across traces, provider routing, tools, handoffs, audit, latency, replay, reviews, tasks, and webhook delivery.</p><pre><code>${snippet}</code></pre></section><section><h2>Providers</h2><div class="grid">${providers}</div></section><section><h2>Handoffs</h2><ul>${handoffs}</ul></section><section><h2>Tools</h2><ul>${tools}</ul></section><section><h2>Reviews</h2><ul>${reviews}</ul></section><section><h2>Tasks</h2><ul>${tasks}</ul></section><section><h2>Integration Events</h2><ul>${integrationEvents}</ul></section></main></body></html>`;
23974
+ return `<!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 Operations Record")}</title><style>body{background:#101417;color:#f9f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.eyebrow{color:#fbbf24;font-size:.8rem;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 #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.card,.primitive{background:#182025;border:1px solid #2d3a43;border-radius:20px;padding:16px}.card span,.muted{color:#a9b4bd}.card strong{display:block;font-size:2rem}section{margin-top:28px}article{display:grid;gap:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#182025;border:1px solid #2d3a43;border-radius:16px;padding:14px}pre{background:#080d10;border:1px solid #2d3a43;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}</style></head><body><main><p class="eyebrow">Portable production proof</p><h1>${escapeHtml40(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml40(record.status)}">${escapeHtml40(record.status)}</p><section class="grid"><div class="card"><span>Events</span><strong>${String(record.summary.eventCount)}</strong></div><div class="card"><span>Turns</span><strong>${String(record.summary.turnCount)}</strong></div><div class="card"><span>Errors</span><strong>${String(record.summary.errorCount)}</strong></div><div class="card"><span>Duration</span><strong>${formatMs4(record.summary.callDurationMs)}</strong></div><div class="card"><span>Audit</span><strong>${String(record.audit?.total ?? 0)}</strong></div><div class="card"><span>Reviews</span><strong>${String(record.reviews?.total ?? 0)}</strong></div><div class="card"><span>Tasks</span><strong>${String(record.tasks?.total ?? 0)}</strong></div><div class="card"><span>Integrations</span><strong>${String(record.integrationEvents?.total ?? 0)}</strong></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceOperationsRecordRoutes(...)</code> gives every call one debuggable object</h2><p class="muted">Use this as the support/debug payload across traces, provider routing, tools, handoffs, audit, latency, replay, reviews, tasks, and webhook delivery.</p><pre><code>${snippet}</code></pre></section><section><h2>Providers</h2><div class="grid">${providers}</div></section><section><h2>Handoffs</h2><ul>${handoffs}</ul></section><section><h2>Tools</h2><ul>${tools}</ul></section><section><h2>Reviews</h2><ul>${reviews}</ul></section><section><h2>Tasks</h2><ul>${tasks}</ul></section><section><h2>Integration Events</h2><ul>${integrationEvents}</ul></section></main></body></html>`;
23670
23975
  };
23671
23976
  var createVoiceOperationsRecordRoutes = (options) => {
23672
23977
  const path = options.path ?? "/api/voice-operations/:sessionId";
23673
23978
  const htmlPath = options.htmlPath === undefined ? "/voice-operations/:sessionId" : options.htmlPath;
23674
- const routes = new Elysia38({
23979
+ const routes = new Elysia39({
23675
23980
  name: options.name ?? "absolutejs-voice-operations-record"
23676
23981
  });
23677
23982
  const buildRecord = (sessionId) => buildVoiceOperationsRecord({
@@ -23704,7 +24009,7 @@ var createVoiceOperationsRecordRoutes = (options) => {
23704
24009
  return routes;
23705
24010
  };
23706
24011
  // src/incidentBundle.ts
23707
- import { Elysia as Elysia39 } from "elysia";
24012
+ import { Elysia as Elysia40 } from "elysia";
23708
24013
  var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
23709
24014
  if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
23710
24015
  return false;
@@ -23903,7 +24208,7 @@ var buildVoiceIncidentBundle = async (options) => {
23903
24208
  var createVoiceIncidentBundleRoutes = (options) => {
23904
24209
  const path = options.path ?? "/api/voice-incidents/:sessionId";
23905
24210
  const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
23906
- const routes = new Elysia39({
24211
+ const routes = new Elysia40({
23907
24212
  name: options.name ?? "absolutejs-voice-incident-bundle"
23908
24213
  });
23909
24214
  const getSessionId = (params) => params.sessionId ?? "";
@@ -24104,19 +24409,19 @@ var summarizeVoiceOpsStatus = async (options) => {
24104
24409
  };
24105
24410
  };
24106
24411
  // src/opsStatusRoutes.ts
24107
- import { Elysia as Elysia40 } from "elysia";
24108
- var escapeHtml40 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
24412
+ import { Elysia as Elysia41 } from "elysia";
24413
+ var escapeHtml41 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
24109
24414
  var renderVoiceOpsStatusHTML = (report, options = {}) => {
24110
24415
  const title = options.title ?? "AbsoluteJS Voice Ops Status";
24111
24416
  const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
24112
24417
  const value = "recovered" in surface ? surface.total === 0 ? "0 events" : `${surface.recovered}/${surface.total}` : ("auditTotal" in surface) ? `${surface.auditTotal + surface.traceTotal} deliveries` : ("total" in surface) ? `${Math.max(surface.total - ("failed" in surface ? surface.failed : ("degraded" in surface) ? surface.degraded : 0), 0)}/${surface.total}` : surface.status;
24113
- return `<article class="surface ${escapeHtml40(surface.status)}"><span>${escapeHtml40(surface.status.toUpperCase())}</span><h2>${escapeHtml40(key)}</h2><strong>${escapeHtml40(value)}</strong></article>`;
24418
+ return `<article class="surface ${escapeHtml41(surface.status)}"><span>${escapeHtml41(surface.status.toUpperCase())}</span><h2>${escapeHtml41(key)}</h2><strong>${escapeHtml41(value)}</strong></article>`;
24114
24419
  }).join("");
24115
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml40(title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero{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}.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;font-weight:900;padding:8px 12px}.surfaces{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.surface{background:#151d26;border:1px solid #283544;border-radius:20px;padding:18px}.surface span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.surface strong{font-size:1.5rem}.pass{border-color:rgba(34,197,94,.55)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Ops status</p><h1>${escapeHtml40(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml40(report.status)}">Overall: ${escapeHtml40(report.status.toUpperCase())}</p><p>${report.passed}/${report.total} checks passing</p></section><section class="surfaces">${surfaces || '<article class="surface pass"><span>PASS</span><h2>No checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
24420
+ 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{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero{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}.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;font-weight:900;padding:8px 12px}.surfaces{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.surface{background:#151d26;border:1px solid #283544;border-radius:20px;padding:18px}.surface span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.surface strong{font-size:1.5rem}.pass{border-color:rgba(34,197,94,.55)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Ops status</p><h1>${escapeHtml41(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml41(report.status)}">Overall: ${escapeHtml41(report.status.toUpperCase())}</p><p>${report.passed}/${report.total} checks passing</p></section><section class="surfaces">${surfaces || '<article class="surface pass"><span>PASS</span><h2>No checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
24116
24421
  };
24117
24422
  var createVoiceOpsStatusRoutes = (options) => {
24118
24423
  const path = options.path ?? "/api/voice/ops-status";
24119
- const routes = new Elysia40({
24424
+ const routes = new Elysia41({
24120
24425
  name: options.name ?? "absolutejs-voice-ops-status"
24121
24426
  });
24122
24427
  routes.get(path, async () => summarizeVoiceOpsStatus(options));
@@ -24549,8 +24854,8 @@ var createVoiceTTSProviderRouter = (options) => {
24549
24854
  };
24550
24855
  };
24551
24856
  // src/traceDeliveryRoutes.ts
24552
- import { Elysia as Elysia41 } from "elysia";
24553
- var escapeHtml41 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
24857
+ import { Elysia as Elysia42 } from "elysia";
24858
+ var escapeHtml42 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
24554
24859
  var getString16 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
24555
24860
  var getNumber11 = (value) => {
24556
24861
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -24631,14 +24936,14 @@ var renderSinkResults2 = (delivery) => {
24631
24936
  if (entries.length === 0) {
24632
24937
  return "<p>No sink delivery attempts recorded yet.</p>";
24633
24938
  }
24634
- return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml41(sinkId)}</strong>: ${escapeHtml41(result.status)}${result.deliveredTo ? ` to ${escapeHtml41(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml41(result.error)})` : ""}</li>`).join("")}</ul>`;
24939
+ return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml42(sinkId)}</strong>: ${escapeHtml42(result.status)}${result.deliveredTo ? ` to ${escapeHtml42(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml42(result.error)})` : ""}</li>`).join("")}</ul>`;
24635
24940
  };
24636
- var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml41(event.type)} <small>${escapeHtml41(event.id)}</small>${event.sessionId ? ` session=${escapeHtml41(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
24941
+ var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml42(event.type)} <small>${escapeHtml42(event.id)}</small>${event.sessionId ? ` session=${escapeHtml42(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
24637
24942
  var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
24638
24943
  const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
24639
- const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml41(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
24640
- const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml41(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml41(delivery.deliveryStatus)}</span><h2>${escapeHtml41(delivery.id)}</h2><p>${escapeHtml41(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml41(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml41(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
24641
- 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{background:#0f1318;color:#f4efe1;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(14,165,233,.14));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.grid{display:grid;gap:12px;grid-template-columns:repeat(4,1fr);margin-bottom:16px}.grid article,.delivery{background:#151b22;border:1px solid #26313d;border-radius:22px;padding:18px}.grid span,.delivery span{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.grid strong{display:block;font-size:2rem}.deliveries{display:grid;gap:14px}.delivery.failed{border-color:rgba(239,68,68,.75)}.delivery.pending{border-color:rgba(245,158,11,.7)}.delivery.delivered{border-color:rgba(34,197,94,.55)}.delivery.skipped{border-color:rgba(148,163,184,.6)}.head{align-items:start;display:flex;gap:14px;justify-content:space-between}.delivery h2{font-size:1.05rem;margin:.3rem 0;overflow-wrap:anywhere}.delivery h3{margin:1rem 0 .3rem}.delivery p,.delivery li{color:#c8d0d8}.error{color:#fecaca!important}button{background:#86efac;border:0;border-radius:999px;color:#07111f;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}@media(max-width:760px){main{padding:20px}.grid{grid-template-columns:1fr 1fr}.head{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Trace export health</p><h1>${escapeHtml41(title)}</h1><p>Checked ${escapeHtml41(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid3(report)}<section class="deliveries">${rows || "<p>No trace deliveries match this filter.</p>"}</section></main></body></html>`;
24944
+ const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml42(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
24945
+ const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml42(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml42(delivery.deliveryStatus)}</span><h2>${escapeHtml42(delivery.id)}</h2><p>${escapeHtml42(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml42(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml42(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
24946
+ 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:#0f1318;color:#f4efe1;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(14,165,233,.14));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.grid{display:grid;gap:12px;grid-template-columns:repeat(4,1fr);margin-bottom:16px}.grid article,.delivery{background:#151b22;border:1px solid #26313d;border-radius:22px;padding:18px}.grid span,.delivery span{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.grid strong{display:block;font-size:2rem}.deliveries{display:grid;gap:14px}.delivery.failed{border-color:rgba(239,68,68,.75)}.delivery.pending{border-color:rgba(245,158,11,.7)}.delivery.delivered{border-color:rgba(34,197,94,.55)}.delivery.skipped{border-color:rgba(148,163,184,.6)}.head{align-items:start;display:flex;gap:14px;justify-content:space-between}.delivery h2{font-size:1.05rem;margin:.3rem 0;overflow-wrap:anywhere}.delivery h3{margin:1rem 0 .3rem}.delivery p,.delivery li{color:#c8d0d8}.error{color:#fecaca!important}button{background:#86efac;border:0;border-radius:999px;color:#07111f;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}@media(max-width:760px){main{padding:20px}.grid{grid-template-columns:1fr 1fr}.head{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Trace export health</p><h1>${escapeHtml42(title)}</h1><p>Checked ${escapeHtml42(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid3(report)}<section class="deliveries">${rows || "<p>No trace deliveries match this filter.</p>"}</section></main></body></html>`;
24642
24947
  };
24643
24948
  var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
24644
24949
  var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
@@ -24658,7 +24963,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
24658
24963
  const path = options.path ?? "/api/voice-trace-deliveries";
24659
24964
  const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
24660
24965
  const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
24661
- const routes = new Elysia41({
24966
+ const routes = new Elysia42({
24662
24967
  name: options.name ?? "absolutejs-voice-trace-deliveries"
24663
24968
  }).get(path, createVoiceTraceDeliveryJSONHandler(options));
24664
24969
  if (htmlPath !== false) {
@@ -25282,7 +25587,7 @@ var createVoiceMemoryStore = () => {
25282
25587
  return { get, getOrCreate, list, remove, set };
25283
25588
  };
25284
25589
  // src/opsWebhook.ts
25285
- import { Elysia as Elysia42 } from "elysia";
25590
+ import { Elysia as Elysia43 } from "elysia";
25286
25591
  var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
25287
25592
  var signVoiceOpsWebhookBody = async (input) => {
25288
25593
  const encoder = new TextEncoder;
@@ -25412,7 +25717,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
25412
25717
  };
25413
25718
  var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
25414
25719
  const path = options.path ?? "/api/voice-ops/webhook";
25415
- return new Elysia42().post(path, async ({ body, request, set }) => {
25720
+ return new Elysia43().post(path, async ({ body, request, set }) => {
25416
25721
  const bodyText = typeof body === "string" ? body : JSON.stringify(body);
25417
25722
  if (options.signingSecret) {
25418
25723
  const verification = await verifyVoiceOpsWebhookSignature({
@@ -26256,6 +26561,7 @@ export {
26256
26561
  withVoiceOpsTaskId,
26257
26562
  withVoiceIntegrationEventId,
26258
26563
  voiceTelephonyOutcomeToRouteResult,
26564
+ voiceComplianceRedactionDefaults,
26259
26565
  voice,
26260
26566
  verifyVoiceTwilioWebhookSignature,
26261
26567
  verifyVoiceTelnyxWebhookSignature,
@@ -26365,6 +26671,8 @@ export {
26365
26671
  renderVoiceDemoReadyHTML,
26366
26672
  renderVoiceDeliverySinkHTML,
26367
26673
  renderVoiceDeliveryRuntimeHTML,
26674
+ renderVoiceDataControlMarkdown,
26675
+ renderVoiceDataControlHTML,
26368
26676
  renderVoiceCampaignsHTML,
26369
26677
  renderVoiceCampaignObservabilityHTML,
26370
26678
  renderVoiceCallReviewMarkdown,
@@ -26422,6 +26730,7 @@ export {
26422
26730
  deliverVoiceAuditEventsToSinks,
26423
26731
  decodeTwilioMulawBase64,
26424
26732
  deadLetterVoiceOpsTask,
26733
+ createVoiceZeroRetentionPolicy,
26425
26734
  createVoiceZendeskTicketUpdateSink,
26426
26735
  createVoiceZendeskTicketSyncSinks,
26427
26736
  createVoiceZendeskTicketSink,
@@ -26609,6 +26918,7 @@ export {
26609
26918
  createVoiceDeliveryRuntimeRoutes,
26610
26919
  createVoiceDeliveryRuntimePresetConfig,
26611
26920
  createVoiceDeliveryRuntime,
26921
+ createVoiceDataControlRoutes,
26612
26922
  createVoiceCampaignWorkerLoop,
26613
26923
  createVoiceCampaignWorker,
26614
26924
  createVoiceCampaignTelephonyOutcomeHandler,
@@ -26690,6 +27000,7 @@ export {
26690
27000
  buildVoiceDeliverySinkReport,
26691
27001
  buildVoiceDeliveryRuntimeReport,
26692
27002
  buildVoiceDataRetentionPlan,
27003
+ buildVoiceDataControlReport,
26693
27004
  buildVoiceCampaignObservabilityReport,
26694
27005
  buildVoiceAuditTrailReport,
26695
27006
  buildVoiceAuditExport,