@absolutejs/voice 0.0.22-beta.500 → 0.0.22-beta.501
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/angular/index.d.ts +6 -0
- package/dist/angular/index.js +605 -264
- package/dist/angular/voice-cost-dashboard.service.d.ts +15 -0
- package/dist/angular/voice-live-call-viewer.service.d.ts +16 -0
- package/dist/angular/voice-replay-timeline.service.d.ts +13 -0
- package/dist/svelte/createVoiceCostDashboard.d.ts +13 -0
- package/dist/svelte/createVoiceLiveCallViewer.d.ts +26 -0
- package/dist/svelte/createVoiceReplayTimeline.d.ts +13 -0
- package/dist/svelte/index.d.ts +6 -0
- package/dist/svelte/index.js +376 -0
- package/dist/vue/VoiceCostDashboard.d.ts +57 -0
- package/dist/vue/VoiceLiveCallViewer.d.ts +35 -0
- package/dist/vue/VoiceReplayTimeline.d.ts +17 -0
- package/dist/vue/index.d.ts +3 -0
- package/dist/vue/index.js +570 -12
- package/package.json +1 -1
package/dist/vue/index.js
CHANGED
|
@@ -12082,14 +12082,569 @@ var VoiceWidget = defineComponent18({
|
|
|
12082
12082
|
};
|
|
12083
12083
|
}
|
|
12084
12084
|
});
|
|
12085
|
+
// src/vue/VoiceCostDashboard.ts
|
|
12086
|
+
import { computed as computed11, defineComponent as defineComponent19, h as h19 } from "vue";
|
|
12087
|
+
|
|
12088
|
+
// src/client/costDashboard.ts
|
|
12089
|
+
var padTwo = (value) => String(value).padStart(2, "0");
|
|
12090
|
+
var formatBucketKey = (epochMs, bucketBy) => {
|
|
12091
|
+
const date = new Date(epochMs);
|
|
12092
|
+
const y = date.getUTCFullYear();
|
|
12093
|
+
const m = padTwo(date.getUTCMonth() + 1);
|
|
12094
|
+
const d = padTwo(date.getUTCDate());
|
|
12095
|
+
const h19 = padTwo(date.getUTCHours());
|
|
12096
|
+
if (bucketBy === "month")
|
|
12097
|
+
return `${y}-${m}`;
|
|
12098
|
+
if (bucketBy === "day")
|
|
12099
|
+
return `${y}-${m}-${d}`;
|
|
12100
|
+
return `${y}-${m}-${d}T${h19}`;
|
|
12101
|
+
};
|
|
12102
|
+
var isCostBreakdown = (value) => Boolean(value) && typeof value === "object" && typeof value.totalUsd === "number";
|
|
12103
|
+
var emptyBucket = (bucketKey) => ({
|
|
12104
|
+
bucketKey,
|
|
12105
|
+
callCount: 0,
|
|
12106
|
+
llmUsd: 0,
|
|
12107
|
+
sttUsd: 0,
|
|
12108
|
+
telephonyMinutes: 0,
|
|
12109
|
+
telephonyUsd: 0,
|
|
12110
|
+
totalUsd: 0,
|
|
12111
|
+
ttsUsd: 0
|
|
12112
|
+
});
|
|
12113
|
+
var accumulate = (bucket, payload) => {
|
|
12114
|
+
bucket.callCount += 1;
|
|
12115
|
+
bucket.llmUsd += payload.llm.usd;
|
|
12116
|
+
bucket.sttUsd += payload.stt.usd;
|
|
12117
|
+
bucket.ttsUsd += payload.tts.usd;
|
|
12118
|
+
bucket.telephonyUsd += payload.telephony.usd;
|
|
12119
|
+
bucket.telephonyMinutes += payload.telephony.minutes;
|
|
12120
|
+
bucket.totalUsd += payload.totalUsd;
|
|
12121
|
+
};
|
|
12122
|
+
var roundCurrency = (bucket) => {
|
|
12123
|
+
bucket.llmUsd = Math.round(bucket.llmUsd * 1e6) / 1e6;
|
|
12124
|
+
bucket.sttUsd = Math.round(bucket.sttUsd * 1e6) / 1e6;
|
|
12125
|
+
bucket.ttsUsd = Math.round(bucket.ttsUsd * 1e6) / 1e6;
|
|
12126
|
+
bucket.telephonyUsd = Math.round(bucket.telephonyUsd * 1e6) / 1e6;
|
|
12127
|
+
bucket.totalUsd = Math.round(bucket.totalUsd * 1e6) / 1e6;
|
|
12128
|
+
};
|
|
12129
|
+
var buildVoiceCostDashboardReport = (options) => {
|
|
12130
|
+
const bucketBy = options.bucketBy ?? "day";
|
|
12131
|
+
const fromMs = options.fromMs ?? Number.NEGATIVE_INFINITY;
|
|
12132
|
+
const toMs = options.toMs ?? Number.POSITIVE_INFINITY;
|
|
12133
|
+
const buckets = new Map;
|
|
12134
|
+
const grandTotal = emptyBucket("total");
|
|
12135
|
+
let minMs = Number.POSITIVE_INFINITY;
|
|
12136
|
+
let maxMs = Number.NEGATIVE_INFINITY;
|
|
12137
|
+
for (const event of options.events) {
|
|
12138
|
+
if (event.type !== "cost.ready")
|
|
12139
|
+
continue;
|
|
12140
|
+
if (event.at < fromMs || event.at > toMs)
|
|
12141
|
+
continue;
|
|
12142
|
+
if (!isCostBreakdown(event.payload))
|
|
12143
|
+
continue;
|
|
12144
|
+
minMs = Math.min(minMs, event.at);
|
|
12145
|
+
maxMs = Math.max(maxMs, event.at);
|
|
12146
|
+
const bucketKey = formatBucketKey(event.at, bucketBy);
|
|
12147
|
+
let bucket = buckets.get(bucketKey);
|
|
12148
|
+
if (!bucket) {
|
|
12149
|
+
bucket = emptyBucket(bucketKey);
|
|
12150
|
+
buckets.set(bucketKey, bucket);
|
|
12151
|
+
}
|
|
12152
|
+
accumulate(bucket, event.payload);
|
|
12153
|
+
accumulate(grandTotal, event.payload);
|
|
12154
|
+
}
|
|
12155
|
+
for (const bucket of buckets.values()) {
|
|
12156
|
+
roundCurrency(bucket);
|
|
12157
|
+
}
|
|
12158
|
+
roundCurrency(grandTotal);
|
|
12159
|
+
return {
|
|
12160
|
+
buckets: Array.from(buckets.values()).sort((a, b) => a.bucketKey.localeCompare(b.bucketKey)),
|
|
12161
|
+
generatedAt: Date.now(),
|
|
12162
|
+
grandTotal,
|
|
12163
|
+
windowEndMs: Number.isFinite(maxMs) ? maxMs : 0,
|
|
12164
|
+
windowStartMs: Number.isFinite(minMs) ? minMs : 0
|
|
12165
|
+
};
|
|
12166
|
+
};
|
|
12167
|
+
|
|
12168
|
+
// src/vue/VoiceCostDashboard.ts
|
|
12169
|
+
var formatUsd = (value, currency = "USD") => new Intl.NumberFormat("en-US", {
|
|
12170
|
+
currency,
|
|
12171
|
+
maximumFractionDigits: 4,
|
|
12172
|
+
minimumFractionDigits: 2,
|
|
12173
|
+
style: "currency"
|
|
12174
|
+
}).format(value);
|
|
12175
|
+
var formatInteger = (value) => new Intl.NumberFormat("en-US").format(value);
|
|
12176
|
+
var renderRow = (bucket, currency, isTotal) => h19("tr", {
|
|
12177
|
+
"data-bucket-key": bucket.bucketKey,
|
|
12178
|
+
style: {
|
|
12179
|
+
borderTop: isTotal ? "2px solid rgba(255,255,255,0.15)" : undefined,
|
|
12180
|
+
fontWeight: isTotal ? 600 : undefined
|
|
12181
|
+
}
|
|
12182
|
+
}, [
|
|
12183
|
+
h19("td", { style: { padding: "8px 12px" } }, bucket.bucketKey),
|
|
12184
|
+
h19("td", { style: { padding: "8px 12px", textAlign: "right" } }, formatInteger(bucket.callCount)),
|
|
12185
|
+
h19("td", { style: { padding: "8px 12px", textAlign: "right" } }, formatUsd(bucket.llmUsd, currency)),
|
|
12186
|
+
h19("td", { style: { padding: "8px 12px", textAlign: "right" } }, formatUsd(bucket.ttsUsd, currency)),
|
|
12187
|
+
h19("td", { style: { padding: "8px 12px", textAlign: "right" } }, formatUsd(bucket.sttUsd, currency)),
|
|
12188
|
+
h19("td", { style: { padding: "8px 12px", textAlign: "right" } }, formatUsd(bucket.telephonyUsd, currency)),
|
|
12189
|
+
h19("td", { style: { padding: "8px 12px", textAlign: "right" } }, formatUsd(bucket.totalUsd, currency))
|
|
12190
|
+
]);
|
|
12191
|
+
var VoiceCostDashboard = defineComponent19({
|
|
12192
|
+
name: "VoiceCostDashboard",
|
|
12193
|
+
props: {
|
|
12194
|
+
bucketBy: {
|
|
12195
|
+
default: "day",
|
|
12196
|
+
type: String
|
|
12197
|
+
},
|
|
12198
|
+
currency: { default: "USD", type: String },
|
|
12199
|
+
emptyMessage: { default: "No cost events in window.", type: String },
|
|
12200
|
+
events: {
|
|
12201
|
+
required: true,
|
|
12202
|
+
type: Array
|
|
12203
|
+
},
|
|
12204
|
+
fromMs: Number,
|
|
12205
|
+
title: { default: "Voice cost dashboard", type: String },
|
|
12206
|
+
toMs: Number
|
|
12207
|
+
},
|
|
12208
|
+
setup(props) {
|
|
12209
|
+
const report = computed11(() => buildVoiceCostDashboardReport({
|
|
12210
|
+
bucketBy: props.bucketBy,
|
|
12211
|
+
events: props.events,
|
|
12212
|
+
fromMs: props.fromMs,
|
|
12213
|
+
toMs: props.toMs
|
|
12214
|
+
}));
|
|
12215
|
+
return () => {
|
|
12216
|
+
const r = report.value;
|
|
12217
|
+
const rows = r.buckets.map((bucket) => renderRow(bucket, props.currency, false));
|
|
12218
|
+
rows.push(renderRow(r.grandTotal, props.currency, true));
|
|
12219
|
+
return h19("section", {
|
|
12220
|
+
"aria-label": "voice-cost-dashboard",
|
|
12221
|
+
class: "absolute-voice-cost-dashboard",
|
|
12222
|
+
style: {
|
|
12223
|
+
background: "#0f172a",
|
|
12224
|
+
borderRadius: "16px",
|
|
12225
|
+
color: "#f8fafc",
|
|
12226
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
12227
|
+
padding: "20px"
|
|
12228
|
+
}
|
|
12229
|
+
}, [
|
|
12230
|
+
h19("header", {
|
|
12231
|
+
style: {
|
|
12232
|
+
alignItems: "baseline",
|
|
12233
|
+
display: "flex",
|
|
12234
|
+
gap: "12px",
|
|
12235
|
+
marginBottom: "12px"
|
|
12236
|
+
}
|
|
12237
|
+
}, [
|
|
12238
|
+
h19("strong", { style: { fontSize: "16px" } }, props.title),
|
|
12239
|
+
h19("span", { style: { fontSize: "13px", opacity: "0.7" } }, `${r.buckets.length} buckets \xB7 grand total ${formatUsd(r.grandTotal.totalUsd, props.currency)}`)
|
|
12240
|
+
]),
|
|
12241
|
+
r.buckets.length === 0 ? h19("p", { style: { fontSize: "13px", opacity: "0.7" } }, props.emptyMessage) : h19("table", {
|
|
12242
|
+
style: {
|
|
12243
|
+
borderCollapse: "collapse",
|
|
12244
|
+
fontSize: "13px",
|
|
12245
|
+
width: "100%"
|
|
12246
|
+
}
|
|
12247
|
+
}, [
|
|
12248
|
+
h19("thead", [
|
|
12249
|
+
h19("tr", { style: { opacity: "0.7", textAlign: "left" } }, [
|
|
12250
|
+
h19("th", { style: { padding: "8px 12px" } }, "Bucket"),
|
|
12251
|
+
h19("th", { style: { padding: "8px 12px", textAlign: "right" } }, "Calls"),
|
|
12252
|
+
h19("th", { style: { padding: "8px 12px", textAlign: "right" } }, "LLM"),
|
|
12253
|
+
h19("th", { style: { padding: "8px 12px", textAlign: "right" } }, "TTS"),
|
|
12254
|
+
h19("th", { style: { padding: "8px 12px", textAlign: "right" } }, "STT"),
|
|
12255
|
+
h19("th", { style: { padding: "8px 12px", textAlign: "right" } }, "Tel."),
|
|
12256
|
+
h19("th", { style: { padding: "8px 12px", textAlign: "right" } }, "Total")
|
|
12257
|
+
])
|
|
12258
|
+
]),
|
|
12259
|
+
h19("tbody", rows)
|
|
12260
|
+
])
|
|
12261
|
+
]);
|
|
12262
|
+
};
|
|
12263
|
+
}
|
|
12264
|
+
});
|
|
12265
|
+
// src/vue/VoiceLiveCallViewer.ts
|
|
12266
|
+
import {
|
|
12267
|
+
defineComponent as defineComponent20,
|
|
12268
|
+
h as h20,
|
|
12269
|
+
onUnmounted as onUnmounted23,
|
|
12270
|
+
shallowRef as shallowRef22
|
|
12271
|
+
} from "vue";
|
|
12272
|
+
|
|
12273
|
+
// src/client/liveCallViewer.ts
|
|
12274
|
+
var EVENT_BUFFER_LIMIT = 200;
|
|
12275
|
+
var createLiveCallViewer = (options) => {
|
|
12276
|
+
const bufferLimit = options.bufferLimit ?? EVENT_BUFFER_LIMIT;
|
|
12277
|
+
const subscribers = new Set;
|
|
12278
|
+
let state = {
|
|
12279
|
+
agentState: "idle",
|
|
12280
|
+
callDurationMs: 0,
|
|
12281
|
+
events: [],
|
|
12282
|
+
isConnected: true,
|
|
12283
|
+
isLiveListening: true,
|
|
12284
|
+
partialTranscript: "",
|
|
12285
|
+
sessionId: options.sessionId
|
|
12286
|
+
};
|
|
12287
|
+
const startedAt = options.startedAt ?? Date.now();
|
|
12288
|
+
const notify = () => {
|
|
12289
|
+
for (const subscriber of subscribers)
|
|
12290
|
+
subscriber();
|
|
12291
|
+
};
|
|
12292
|
+
const update = (next) => {
|
|
12293
|
+
state = { ...state, ...next };
|
|
12294
|
+
state.callDurationMs = Math.max(0, Date.now() - startedAt);
|
|
12295
|
+
state.agentState = deriveVoiceAgentUIState({
|
|
12296
|
+
hasActivePartial: state.partialTranscript.length > 0,
|
|
12297
|
+
isConnected: state.isConnected,
|
|
12298
|
+
isPlaying: false,
|
|
12299
|
+
isRecording: state.isLiveListening,
|
|
12300
|
+
lastAssistantAt: state.lastAssistantAt,
|
|
12301
|
+
lastTranscriptAt: state.lastTranscriptAt
|
|
12302
|
+
});
|
|
12303
|
+
notify();
|
|
12304
|
+
};
|
|
12305
|
+
const pushEvent = (event) => {
|
|
12306
|
+
const next = state.events.concat(event);
|
|
12307
|
+
if (next.length > bufferLimit) {
|
|
12308
|
+
next.splice(0, next.length - bufferLimit);
|
|
12309
|
+
}
|
|
12310
|
+
update({ events: next });
|
|
12311
|
+
};
|
|
12312
|
+
return {
|
|
12313
|
+
applyControl: (control) => {
|
|
12314
|
+
pushEvent({
|
|
12315
|
+
at: Date.now(),
|
|
12316
|
+
detail: control.reason,
|
|
12317
|
+
kind: "lifecycle",
|
|
12318
|
+
title: `control:${control.type}`
|
|
12319
|
+
});
|
|
12320
|
+
},
|
|
12321
|
+
applyEvent: pushEvent,
|
|
12322
|
+
applyMonitorEvent: ({ payload, type }) => {
|
|
12323
|
+
pushEvent({
|
|
12324
|
+
at: Date.now(),
|
|
12325
|
+
detail: JSON.stringify(payload).slice(0, 240),
|
|
12326
|
+
kind: type === "call.lifecycle" ? "lifecycle" : "lifecycle",
|
|
12327
|
+
title: type
|
|
12328
|
+
});
|
|
12329
|
+
},
|
|
12330
|
+
getState: () => state,
|
|
12331
|
+
noteAgentAudio: (at) => {
|
|
12332
|
+
const ts = at ?? Date.now();
|
|
12333
|
+
update({ lastAssistantAt: ts });
|
|
12334
|
+
pushEvent({
|
|
12335
|
+
at: ts,
|
|
12336
|
+
kind: "agent_audio",
|
|
12337
|
+
title: "Agent audio frame"
|
|
12338
|
+
});
|
|
12339
|
+
},
|
|
12340
|
+
notePartial: (text, at) => {
|
|
12341
|
+
update({ partialTranscript: text });
|
|
12342
|
+
if (text) {
|
|
12343
|
+
pushEvent({
|
|
12344
|
+
at: at ?? Date.now(),
|
|
12345
|
+
detail: text,
|
|
12346
|
+
kind: "transcript",
|
|
12347
|
+
title: "Partial"
|
|
12348
|
+
});
|
|
12349
|
+
}
|
|
12350
|
+
},
|
|
12351
|
+
noteTranscript: (text, at) => {
|
|
12352
|
+
const ts = at ?? Date.now();
|
|
12353
|
+
update({ lastTranscriptAt: ts, partialTranscript: "" });
|
|
12354
|
+
pushEvent({
|
|
12355
|
+
at: ts,
|
|
12356
|
+
detail: text,
|
|
12357
|
+
kind: "transcript",
|
|
12358
|
+
title: "Final transcript"
|
|
12359
|
+
});
|
|
12360
|
+
},
|
|
12361
|
+
reset: (sessionId, startedAtOverride) => {
|
|
12362
|
+
state = {
|
|
12363
|
+
agentState: "idle",
|
|
12364
|
+
callDurationMs: 0,
|
|
12365
|
+
events: [],
|
|
12366
|
+
isConnected: true,
|
|
12367
|
+
isLiveListening: true,
|
|
12368
|
+
partialTranscript: "",
|
|
12369
|
+
sessionId
|
|
12370
|
+
};
|
|
12371
|
+
if (typeof startedAtOverride === "number") {}
|
|
12372
|
+
notify();
|
|
12373
|
+
},
|
|
12374
|
+
subscribe: (subscriber) => {
|
|
12375
|
+
subscribers.add(subscriber);
|
|
12376
|
+
return () => subscribers.delete(subscriber);
|
|
12377
|
+
}
|
|
12378
|
+
};
|
|
12379
|
+
};
|
|
12380
|
+
|
|
12381
|
+
// src/vue/VoiceLiveCallViewer.ts
|
|
12382
|
+
var CATEGORY_COLOR = {
|
|
12383
|
+
agent_audio: "#3b82f6",
|
|
12384
|
+
agent_text: "#3b82f6",
|
|
12385
|
+
lifecycle: "#94a3b8",
|
|
12386
|
+
tool: "#f59e0b",
|
|
12387
|
+
transcript: "#10b981"
|
|
12388
|
+
};
|
|
12389
|
+
var formatRelative = (ms) => {
|
|
12390
|
+
const seconds = Math.max(0, Math.floor(ms / 1000));
|
|
12391
|
+
const minutes = Math.floor(seconds / 60);
|
|
12392
|
+
const remaining = seconds % 60;
|
|
12393
|
+
return `${String(minutes).padStart(2, "0")}:${String(remaining).padStart(2, "0")}`;
|
|
12394
|
+
};
|
|
12395
|
+
var VoiceLiveCallViewer = defineComponent20({
|
|
12396
|
+
name: "VoiceLiveCallViewer",
|
|
12397
|
+
props: {
|
|
12398
|
+
sessionId: { default: "live", type: String },
|
|
12399
|
+
title: { default: "Live call", type: String },
|
|
12400
|
+
viewer: {
|
|
12401
|
+
default: undefined,
|
|
12402
|
+
type: Object
|
|
12403
|
+
}
|
|
12404
|
+
},
|
|
12405
|
+
setup(props) {
|
|
12406
|
+
const owned = !props.viewer;
|
|
12407
|
+
const viewer = props.viewer ?? createLiveCallViewer({ sessionId: props.sessionId });
|
|
12408
|
+
const state = shallowRef22(viewer.getState());
|
|
12409
|
+
const unsubscribe = viewer.subscribe(() => {
|
|
12410
|
+
state.value = viewer.getState();
|
|
12411
|
+
});
|
|
12412
|
+
onUnmounted23(() => {
|
|
12413
|
+
unsubscribe();
|
|
12414
|
+
});
|
|
12415
|
+
return () => {
|
|
12416
|
+
const s = state.value;
|
|
12417
|
+
const firstAt = s.events[0]?.at ?? Date.now();
|
|
12418
|
+
return h20("section", {
|
|
12419
|
+
"aria-label": "voice-live-call-viewer",
|
|
12420
|
+
class: "absolute-voice-live-call-viewer",
|
|
12421
|
+
"data-agent-state": s.agentState,
|
|
12422
|
+
style: {
|
|
12423
|
+
background: "#0f172a",
|
|
12424
|
+
borderRadius: "16px",
|
|
12425
|
+
color: "#f8fafc",
|
|
12426
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
12427
|
+
padding: "20px"
|
|
12428
|
+
}
|
|
12429
|
+
}, [
|
|
12430
|
+
h20("header", {
|
|
12431
|
+
style: {
|
|
12432
|
+
alignItems: "center",
|
|
12433
|
+
display: "flex",
|
|
12434
|
+
gap: "12px",
|
|
12435
|
+
marginBottom: "12px"
|
|
12436
|
+
}
|
|
12437
|
+
}, [
|
|
12438
|
+
h20("strong", { style: { fontSize: "16px" } }, props.title),
|
|
12439
|
+
h20("span", {
|
|
12440
|
+
style: {
|
|
12441
|
+
background: "rgba(59,130,246,0.18)",
|
|
12442
|
+
borderRadius: "999px",
|
|
12443
|
+
fontSize: "11px",
|
|
12444
|
+
padding: "3px 10px",
|
|
12445
|
+
textTransform: "uppercase"
|
|
12446
|
+
}
|
|
12447
|
+
}, s.agentState),
|
|
12448
|
+
h20("span", {
|
|
12449
|
+
style: {
|
|
12450
|
+
fontSize: "13px",
|
|
12451
|
+
marginLeft: "auto",
|
|
12452
|
+
opacity: "0.7"
|
|
12453
|
+
}
|
|
12454
|
+
}, `${s.sessionId} \xB7 ${formatRelative(s.callDurationMs)}`)
|
|
12455
|
+
]),
|
|
12456
|
+
s.partialTranscript ? h20("p", {
|
|
12457
|
+
style: {
|
|
12458
|
+
background: "rgba(16,185,129,0.12)",
|
|
12459
|
+
borderRadius: "12px",
|
|
12460
|
+
fontSize: "13px",
|
|
12461
|
+
margin: "0 0 12px",
|
|
12462
|
+
opacity: "0.95",
|
|
12463
|
+
padding: "10px 12px"
|
|
12464
|
+
}
|
|
12465
|
+
}, `\u201C${s.partialTranscript}\u201D`) : null,
|
|
12466
|
+
h20("ol", {
|
|
12467
|
+
style: {
|
|
12468
|
+
display: "flex",
|
|
12469
|
+
flexDirection: "column",
|
|
12470
|
+
gap: "6px",
|
|
12471
|
+
listStyle: "none",
|
|
12472
|
+
margin: "0",
|
|
12473
|
+
maxHeight: "320px",
|
|
12474
|
+
overflowY: "auto",
|
|
12475
|
+
padding: "0"
|
|
12476
|
+
}
|
|
12477
|
+
}, s.events.map((event, index) => h20("li", {
|
|
12478
|
+
key: `${event.at}-${index}`,
|
|
12479
|
+
style: {
|
|
12480
|
+
alignItems: "center",
|
|
12481
|
+
borderLeft: `3px solid ${CATEGORY_COLOR[event.kind] ?? "#94a3b8"}`,
|
|
12482
|
+
display: "flex",
|
|
12483
|
+
fontSize: "13px",
|
|
12484
|
+
gap: "12px",
|
|
12485
|
+
paddingLeft: "12px"
|
|
12486
|
+
}
|
|
12487
|
+
}, [
|
|
12488
|
+
h20("span", {
|
|
12489
|
+
style: {
|
|
12490
|
+
color: "#cbd5e1",
|
|
12491
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
12492
|
+
fontSize: "12px",
|
|
12493
|
+
width: "60px"
|
|
12494
|
+
}
|
|
12495
|
+
}, formatRelative(event.at - firstAt)),
|
|
12496
|
+
h20("strong", { style: { fontSize: "13px" } }, event.title),
|
|
12497
|
+
event.detail ? h20("span", { style: { opacity: "0.85" } }, event.detail) : null
|
|
12498
|
+
])))
|
|
12499
|
+
]);
|
|
12500
|
+
};
|
|
12501
|
+
}
|
|
12502
|
+
});
|
|
12503
|
+
// src/vue/VoiceReplayTimeline.ts
|
|
12504
|
+
import { computed as computed12, defineComponent as defineComponent21, h as h21 } from "vue";
|
|
12505
|
+
|
|
12506
|
+
// src/client/replayTimeline.ts
|
|
12507
|
+
var categorize = (entry) => {
|
|
12508
|
+
const event = entry.event.toLowerCase();
|
|
12509
|
+
if (event.startsWith("stt.") || event.includes("user"))
|
|
12510
|
+
return "user";
|
|
12511
|
+
if (event.startsWith("tts.") || event.includes("assistant") || event.includes("agent"))
|
|
12512
|
+
return "agent";
|
|
12513
|
+
if (event.startsWith("tool.") || event.includes("tool"))
|
|
12514
|
+
return "tool";
|
|
12515
|
+
return "lifecycle";
|
|
12516
|
+
};
|
|
12517
|
+
var buildReplayTimelineReport = (input) => {
|
|
12518
|
+
const events = [];
|
|
12519
|
+
let summaryAgentTurns = 0;
|
|
12520
|
+
let summaryUserTurns = 0;
|
|
12521
|
+
let summaryToolCalls = 0;
|
|
12522
|
+
for (const entry of input.artifact.timeline ?? []) {
|
|
12523
|
+
const category = categorize(entry);
|
|
12524
|
+
if (category === "user")
|
|
12525
|
+
summaryUserTurns += 1;
|
|
12526
|
+
if (category === "agent")
|
|
12527
|
+
summaryAgentTurns += 1;
|
|
12528
|
+
if (category === "tool")
|
|
12529
|
+
summaryToolCalls += 1;
|
|
12530
|
+
events.push({
|
|
12531
|
+
at: entry.atMs,
|
|
12532
|
+
category,
|
|
12533
|
+
detail: entry.text ?? entry.reason,
|
|
12534
|
+
durationMs: entry.chunkDurationMs,
|
|
12535
|
+
label: entry.event
|
|
12536
|
+
});
|
|
12537
|
+
}
|
|
12538
|
+
events.sort((a, b) => a.at - b.at);
|
|
12539
|
+
const first = events[0]?.at ?? 0;
|
|
12540
|
+
const last = events.at(-1)?.at ?? first;
|
|
12541
|
+
return {
|
|
12542
|
+
duration: last - first,
|
|
12543
|
+
events,
|
|
12544
|
+
metadata: {
|
|
12545
|
+
artifactId: input.artifact.id ?? "",
|
|
12546
|
+
title: input.artifact.title
|
|
12547
|
+
},
|
|
12548
|
+
startedAt: first,
|
|
12549
|
+
summary: {
|
|
12550
|
+
agentTurns: summaryAgentTurns,
|
|
12551
|
+
toolCalls: summaryToolCalls,
|
|
12552
|
+
userTurns: summaryUserTurns
|
|
12553
|
+
}
|
|
12554
|
+
};
|
|
12555
|
+
};
|
|
12556
|
+
|
|
12557
|
+
// src/vue/VoiceReplayTimeline.ts
|
|
12558
|
+
var CATEGORY_COLOR2 = {
|
|
12559
|
+
agent: "#3b82f6",
|
|
12560
|
+
lifecycle: "#94a3b8",
|
|
12561
|
+
tool: "#f59e0b",
|
|
12562
|
+
user: "#10b981"
|
|
12563
|
+
};
|
|
12564
|
+
var formatRelative2 = (ms) => {
|
|
12565
|
+
const seconds = Math.max(0, Math.floor(ms / 1000));
|
|
12566
|
+
const minutes = Math.floor(seconds / 60);
|
|
12567
|
+
const remaining = seconds % 60;
|
|
12568
|
+
return `${String(minutes).padStart(2, "0")}:${String(remaining).padStart(2, "0")}`;
|
|
12569
|
+
};
|
|
12570
|
+
var VoiceReplayTimeline = defineComponent21({
|
|
12571
|
+
name: "VoiceReplayTimeline",
|
|
12572
|
+
props: {
|
|
12573
|
+
artifact: {
|
|
12574
|
+
required: true,
|
|
12575
|
+
type: Object
|
|
12576
|
+
},
|
|
12577
|
+
title: String
|
|
12578
|
+
},
|
|
12579
|
+
setup(props) {
|
|
12580
|
+
const report = computed12(() => buildReplayTimelineReport({ artifact: props.artifact }));
|
|
12581
|
+
return () => {
|
|
12582
|
+
const r = report.value;
|
|
12583
|
+
return h21("section", {
|
|
12584
|
+
"aria-label": "voice-replay-timeline",
|
|
12585
|
+
class: "absolute-voice-replay-timeline",
|
|
12586
|
+
style: {
|
|
12587
|
+
background: "#0f172a",
|
|
12588
|
+
borderRadius: "16px",
|
|
12589
|
+
color: "#f8fafc",
|
|
12590
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
12591
|
+
padding: "20px"
|
|
12592
|
+
}
|
|
12593
|
+
}, [
|
|
12594
|
+
h21("header", {
|
|
12595
|
+
style: {
|
|
12596
|
+
alignItems: "baseline",
|
|
12597
|
+
display: "flex",
|
|
12598
|
+
gap: "12px",
|
|
12599
|
+
marginBottom: "12px"
|
|
12600
|
+
}
|
|
12601
|
+
}, [
|
|
12602
|
+
h21("strong", { style: { fontSize: "16px" } }, props.title ?? r.metadata.title ?? "Replay"),
|
|
12603
|
+
h21("span", { style: { fontSize: "13px", opacity: "0.7" } }, `${r.events.length} events \xB7 ${r.summary.userTurns} user \xB7 ${r.summary.agentTurns} agent \xB7 ${r.summary.toolCalls} tool`)
|
|
12604
|
+
]),
|
|
12605
|
+
r.events.length === 0 ? h21("p", { style: { fontSize: "13px", opacity: "0.7" } }, "No timeline events.") : h21("ol", {
|
|
12606
|
+
style: {
|
|
12607
|
+
display: "flex",
|
|
12608
|
+
flexDirection: "column",
|
|
12609
|
+
gap: "6px",
|
|
12610
|
+
listStyle: "none",
|
|
12611
|
+
margin: "0",
|
|
12612
|
+
padding: "0"
|
|
12613
|
+
}
|
|
12614
|
+
}, r.events.map((event, index) => h21("li", {
|
|
12615
|
+
key: `${event.at}-${index}`,
|
|
12616
|
+
style: {
|
|
12617
|
+
alignItems: "center",
|
|
12618
|
+
borderLeft: `3px solid ${CATEGORY_COLOR2[event.category]}`,
|
|
12619
|
+
display: "flex",
|
|
12620
|
+
fontSize: "13px",
|
|
12621
|
+
gap: "12px",
|
|
12622
|
+
paddingLeft: "12px"
|
|
12623
|
+
}
|
|
12624
|
+
}, [
|
|
12625
|
+
h21("span", {
|
|
12626
|
+
style: {
|
|
12627
|
+
color: "#cbd5e1",
|
|
12628
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
12629
|
+
fontSize: "12px",
|
|
12630
|
+
width: "60px"
|
|
12631
|
+
}
|
|
12632
|
+
}, formatRelative2(event.at - r.startedAt)),
|
|
12633
|
+
h21("strong", { style: { fontSize: "13px" } }, event.label),
|
|
12634
|
+
event.detail ? h21("span", { style: { opacity: "0.85" } }, event.detail) : null
|
|
12635
|
+
])))
|
|
12636
|
+
]);
|
|
12637
|
+
};
|
|
12638
|
+
}
|
|
12639
|
+
});
|
|
12085
12640
|
// src/vue/useVoiceTraceTimeline.ts
|
|
12086
|
-
import { onUnmounted as
|
|
12641
|
+
import { onUnmounted as onUnmounted24, ref as ref19, shallowRef as shallowRef23 } from "vue";
|
|
12087
12642
|
function useVoiceTraceTimeline(path = "/api/voice-traces", options = {}) {
|
|
12088
12643
|
const store = createVoiceTraceTimelineStore(path, options);
|
|
12089
|
-
const error =
|
|
12090
|
-
const isLoading =
|
|
12091
|
-
const report =
|
|
12092
|
-
const updatedAt =
|
|
12644
|
+
const error = ref19(null);
|
|
12645
|
+
const isLoading = ref19(false);
|
|
12646
|
+
const report = shallowRef23(null);
|
|
12647
|
+
const updatedAt = ref19(undefined);
|
|
12093
12648
|
const sync = () => {
|
|
12094
12649
|
const snapshot = store.getSnapshot();
|
|
12095
12650
|
error.value = snapshot.error;
|
|
@@ -12100,7 +12655,7 @@ function useVoiceTraceTimeline(path = "/api/voice-traces", options = {}) {
|
|
|
12100
12655
|
const unsubscribe = store.subscribe(sync);
|
|
12101
12656
|
sync();
|
|
12102
12657
|
store.refresh().catch(() => {});
|
|
12103
|
-
|
|
12658
|
+
onUnmounted24(() => {
|
|
12104
12659
|
unsubscribe();
|
|
12105
12660
|
store.close();
|
|
12106
12661
|
});
|
|
@@ -12113,7 +12668,7 @@ function useVoiceTraceTimeline(path = "/api/voice-traces", options = {}) {
|
|
|
12113
12668
|
};
|
|
12114
12669
|
}
|
|
12115
12670
|
// src/vue/useVoiceWorkflowStatus.ts
|
|
12116
|
-
import { onMounted as onMounted10, onUnmounted as
|
|
12671
|
+
import { onMounted as onMounted10, onUnmounted as onUnmounted25, ref as ref20, shallowRef as shallowRef24 } from "vue";
|
|
12117
12672
|
|
|
12118
12673
|
// src/client/workflowStatus.ts
|
|
12119
12674
|
var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
|
|
@@ -12197,10 +12752,10 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
|
|
|
12197
12752
|
// src/vue/useVoiceWorkflowStatus.ts
|
|
12198
12753
|
function useVoiceWorkflowStatus(path = "/evals/scenarios/json", options = {}) {
|
|
12199
12754
|
const store = createVoiceWorkflowStatusStore(path, options);
|
|
12200
|
-
const error =
|
|
12201
|
-
const isLoading =
|
|
12202
|
-
const report =
|
|
12203
|
-
const updatedAt =
|
|
12755
|
+
const error = ref20(null);
|
|
12756
|
+
const isLoading = ref20(false);
|
|
12757
|
+
const report = shallowRef24(undefined);
|
|
12758
|
+
const updatedAt = ref20(undefined);
|
|
12204
12759
|
const sync = () => {
|
|
12205
12760
|
const snapshot = store.getSnapshot();
|
|
12206
12761
|
error.value = snapshot.error;
|
|
@@ -12213,7 +12768,7 @@ function useVoiceWorkflowStatus(path = "/evals/scenarios/json", options = {}) {
|
|
|
12213
12768
|
onMounted10(() => {
|
|
12214
12769
|
store.refresh().catch(() => {});
|
|
12215
12770
|
});
|
|
12216
|
-
|
|
12771
|
+
onUnmounted25(() => {
|
|
12217
12772
|
unsubscribe();
|
|
12218
12773
|
store.close();
|
|
12219
12774
|
});
|
|
@@ -12257,6 +12812,7 @@ export {
|
|
|
12257
12812
|
VoiceSessionSnapshot,
|
|
12258
12813
|
VoiceSessionObservability,
|
|
12259
12814
|
VoiceRoutingStatus,
|
|
12815
|
+
VoiceReplayTimeline,
|
|
12260
12816
|
VoiceReconnectProfileEvidence,
|
|
12261
12817
|
VoiceReadinessFailures,
|
|
12262
12818
|
VoiceProviderStatus,
|
|
@@ -12267,6 +12823,8 @@ export {
|
|
|
12267
12823
|
VoicePlatformCoverage,
|
|
12268
12824
|
VoiceOpsStatus,
|
|
12269
12825
|
VoiceOpsActionCenter,
|
|
12826
|
+
VoiceLiveCallViewer,
|
|
12270
12827
|
VoiceDeliveryRuntime,
|
|
12828
|
+
VoiceCostDashboard,
|
|
12271
12829
|
VoiceCallDebuggerLaunch
|
|
12272
12830
|
};
|