@absolutejs/voice 0.0.22-beta.198 → 0.0.22-beta.199
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 +65 -2
- package/dist/operationsRecord.d.ts +21 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24226,6 +24226,34 @@ var toTool = (event) => ({
|
|
|
24226
24226
|
toolName: getString17(event.payload.toolName),
|
|
24227
24227
|
turnId: event.turnId
|
|
24228
24228
|
});
|
|
24229
|
+
var toProviderDecision = (event) => {
|
|
24230
|
+
const provider = getString17(event.payload.provider) ?? getString17(event.payload.selectedProvider) ?? getString17(event.payload.fallbackProvider) ?? getString17(event.payload.variantId);
|
|
24231
|
+
const status = getString17(event.payload.providerStatus) ?? getString17(event.payload.status) ?? getString17(event.payload.reason);
|
|
24232
|
+
const error = getString17(event.payload.error);
|
|
24233
|
+
const elapsedMs = getNumber10(event.payload.elapsedMs) ?? getNumber10(event.payload.latencyMs) ?? getNumber10(event.payload.durationMs);
|
|
24234
|
+
if (!provider && !status && !error && elapsedMs === undefined) {
|
|
24235
|
+
return;
|
|
24236
|
+
}
|
|
24237
|
+
return {
|
|
24238
|
+
at: event.at,
|
|
24239
|
+
elapsedMs,
|
|
24240
|
+
error,
|
|
24241
|
+
fallbackProvider: getString17(event.payload.fallbackProvider),
|
|
24242
|
+
provider,
|
|
24243
|
+
reason: getString17(event.payload.reason),
|
|
24244
|
+
selectedProvider: getString17(event.payload.selectedProvider),
|
|
24245
|
+
status,
|
|
24246
|
+
type: event.type,
|
|
24247
|
+
turnId: event.turnId
|
|
24248
|
+
};
|
|
24249
|
+
};
|
|
24250
|
+
var buildTranscript = (replay) => replay.turns.map((turn) => ({
|
|
24251
|
+
assistantReplies: turn.assistantReplies,
|
|
24252
|
+
committedText: turn.committedText,
|
|
24253
|
+
errors: turn.errors.map((error) => getString17(error.error) ?? JSON.stringify(error)).filter((error) => typeof error === "string"),
|
|
24254
|
+
id: turn.id,
|
|
24255
|
+
transcripts: turn.transcripts.map((transcript) => transcript.text).filter((text) => typeof text === "string" && text.length > 0)
|
|
24256
|
+
})).filter((turn) => turn.committedText || turn.assistantReplies.length > 0 || turn.transcripts.length > 0 || turn.errors.length > 0);
|
|
24229
24257
|
var resolveOutcome4 = (events) => {
|
|
24230
24258
|
const agentResults = events.filter((event) => event.type === "agent.result");
|
|
24231
24259
|
return {
|
|
@@ -24281,6 +24309,7 @@ var buildVoiceOperationsRecord = async (options) => {
|
|
|
24281
24309
|
total: integrationEvents.length
|
|
24282
24310
|
} : undefined,
|
|
24283
24311
|
outcome: resolveOutcome4(traceEvents),
|
|
24312
|
+
providerDecisions: traceEvents.map(toProviderDecision).filter((decision) => decision !== undefined),
|
|
24284
24313
|
providers: timelineSession?.providers ?? [],
|
|
24285
24314
|
replay,
|
|
24286
24315
|
reviews: reviews ? {
|
|
@@ -24301,13 +24330,46 @@ var buildVoiceOperationsRecord = async (options) => {
|
|
|
24301
24330
|
} : undefined,
|
|
24302
24331
|
timeline: timelineSession?.events ?? [],
|
|
24303
24332
|
tools: traceEvents.filter((event) => event.type === "agent.tool").map(toTool),
|
|
24304
|
-
traceEvents
|
|
24333
|
+
traceEvents,
|
|
24334
|
+
transcript: buildTranscript(replay)
|
|
24305
24335
|
};
|
|
24306
24336
|
};
|
|
24307
24337
|
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24308
24338
|
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
24339
|
+
var outcomeLabels = (outcome) => [
|
|
24340
|
+
outcome.complete ? "complete" : undefined,
|
|
24341
|
+
outcome.escalated ? "escalated" : undefined,
|
|
24342
|
+
outcome.transferred ? "transferred" : undefined,
|
|
24343
|
+
outcome.voicemail ? "voicemail" : undefined,
|
|
24344
|
+
outcome.noAnswer ? "no-answer" : undefined
|
|
24345
|
+
].filter((label) => label !== undefined);
|
|
24346
|
+
var renderIncidentHandoffMarkdown = (record) => {
|
|
24347
|
+
const outcomes = outcomeLabels(record.outcome);
|
|
24348
|
+
const topErrors = record.traceEvents.filter((event) => event.type === "session.error").map((event) => getString17(event.payload.error)).filter((error) => typeof error === "string").slice(0, 3);
|
|
24349
|
+
const openTasks = record.tasks?.tasks.filter((task) => task.status !== "done").map((task) => task.title).slice(0, 3) ?? [];
|
|
24350
|
+
return [
|
|
24351
|
+
`# Voice incident handoff: ${record.sessionId}`,
|
|
24352
|
+
"",
|
|
24353
|
+
`- Status: ${record.status}`,
|
|
24354
|
+
`- Duration: ${formatMs4(record.summary.callDurationMs)}`,
|
|
24355
|
+
`- Turns: ${String(record.summary.turnCount)}`,
|
|
24356
|
+
`- Errors: ${String(record.summary.errorCount)}`,
|
|
24357
|
+
`- Outcome: ${outcomes.join(", ") || "unknown"}`,
|
|
24358
|
+
`- Providers: ${record.providers.map((provider) => provider.provider).join(", ") || "none recorded"}`,
|
|
24359
|
+
`- Open tasks: ${openTasks.join("; ") || "none"}`,
|
|
24360
|
+
`- Top errors: ${topErrors.join("; ") || "none"}`,
|
|
24361
|
+
"",
|
|
24362
|
+
"## Next checks",
|
|
24363
|
+
"- Review provider decisions and fallback status.",
|
|
24364
|
+
"- Review transcript and assistant replies.",
|
|
24365
|
+
"- Review handoffs, tools, audit, tasks, and integration delivery."
|
|
24366
|
+
].join(`
|
|
24367
|
+
`);
|
|
24368
|
+
};
|
|
24309
24369
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
24310
24370
|
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml41(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>';
|
|
24371
|
+
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml41(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml41(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml41(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml41(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
24372
|
+
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml41(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml41(decision.status ?? decision.type)}</span> ${formatMs4(decision.elapsedMs)}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml41(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml41(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml41(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
24311
24373
|
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml41(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml41(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml41(handoff.status ?? "")}</span><p>${escapeHtml41(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
|
|
24312
24374
|
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml41(tool.toolName ?? "tool")}</strong> <span>${escapeHtml41(tool.status ?? "")}</span> ${formatMs4(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml41(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
|
|
24313
24375
|
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml41(review.title)}</strong> <span>${escapeHtml41(review.summary.outcome ?? "")}</span><p>${escapeHtml41(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
@@ -24327,7 +24389,8 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
24327
24389
|
tasks: opsTasks
|
|
24328
24390
|
})
|
|
24329
24391
|
);`);
|
|
24330
|
-
|
|
24392
|
+
const incidentMarkdown = escapeHtml41(renderIncidentHandoffMarkdown(record));
|
|
24393
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml41(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,.label{color:#a9b4bd}.label{display:block;font-size:.72rem;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.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}.hero-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}.hero-actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.two-column{display:grid;gap:18px;grid-template-columns:minmax(0,1.15fr) minmax(280px,.85fr)}@media(max-width:860px){main{padding:20px}.two-column{grid-template-columns:1fr}}</style></head><body><main><p class="eyebrow">Call log replacement</p><h1>${escapeHtml41(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml41(record.status)}">${escapeHtml41(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#incident-handoff">Incident handoff</a></div><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="two-column"><div><h2 id="transcript">Transcript</h2><ul>${transcript}</ul></div><div><h2 id="provider-decisions">Provider Decisions</h2><ul>${providerDecisions}</ul></div></section><section id="incident-handoff"><h2>Copyable Incident Handoff</h2><p class="muted">Paste this into Slack, Linear, Zendesk, or an incident review.</p><pre><code>${incidentMarkdown}</code></pre></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>Provider Summary</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>`;
|
|
24331
24394
|
};
|
|
24332
24395
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
24333
24396
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
@@ -33,6 +33,25 @@ export type VoiceOperationsRecordTool = {
|
|
|
33
33
|
toolName?: string;
|
|
34
34
|
turnId?: string;
|
|
35
35
|
};
|
|
36
|
+
export type VoiceOperationsRecordTranscriptTurn = {
|
|
37
|
+
assistantReplies: string[];
|
|
38
|
+
committedText?: string;
|
|
39
|
+
errors: string[];
|
|
40
|
+
id: string;
|
|
41
|
+
transcripts: string[];
|
|
42
|
+
};
|
|
43
|
+
export type VoiceOperationsRecordProviderDecision = {
|
|
44
|
+
at: number;
|
|
45
|
+
elapsedMs?: number;
|
|
46
|
+
error?: string;
|
|
47
|
+
fallbackProvider?: string;
|
|
48
|
+
provider?: string;
|
|
49
|
+
reason?: string;
|
|
50
|
+
selectedProvider?: string;
|
|
51
|
+
status?: string;
|
|
52
|
+
type: StoredVoiceTraceEvent['type'];
|
|
53
|
+
turnId?: string;
|
|
54
|
+
};
|
|
36
55
|
export type VoiceOperationsRecordAuditSummary = {
|
|
37
56
|
error: number;
|
|
38
57
|
events: StoredVoiceAuditEvent[];
|
|
@@ -68,6 +87,7 @@ export type VoiceOperationsRecord = {
|
|
|
68
87
|
handoffs: VoiceOperationsRecordAgentHandoff[];
|
|
69
88
|
integrationEvents?: VoiceOperationsRecordIntegrationEventSummary;
|
|
70
89
|
outcome: VoiceOperationsRecordOutcome;
|
|
90
|
+
providerDecisions: VoiceOperationsRecordProviderDecision[];
|
|
71
91
|
providers: VoiceTraceTimelineProviderSummary[];
|
|
72
92
|
replay: VoiceSessionReplay;
|
|
73
93
|
reviews?: VoiceOperationsRecordReviewSummary;
|
|
@@ -78,6 +98,7 @@ export type VoiceOperationsRecord = {
|
|
|
78
98
|
timeline: VoiceTraceTimelineEvent[];
|
|
79
99
|
tools: VoiceOperationsRecordTool[];
|
|
80
100
|
traceEvents: StoredVoiceTraceEvent[];
|
|
101
|
+
transcript: VoiceOperationsRecordTranscriptTurn[];
|
|
81
102
|
};
|
|
82
103
|
export type VoiceOperationsRecordOptions = {
|
|
83
104
|
audit?: VoiceAuditEventStore;
|