@absolutejs/voice 0.0.22-beta.44 → 0.0.22-beta.45

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.
@@ -102,6 +102,30 @@ export type VoiceScenarioEvalReport = {
102
102
  status: VoiceEvalStatus;
103
103
  total: number;
104
104
  };
105
+ export type VoiceScenarioFixture = {
106
+ description?: string;
107
+ events: StoredVoiceTraceEvent[];
108
+ id: string;
109
+ label?: string;
110
+ };
111
+ export type VoiceScenarioFixtureStore = {
112
+ list: () => Promise<VoiceScenarioFixture[]>;
113
+ };
114
+ export type VoiceScenarioFixtureEvalResult = {
115
+ description?: string;
116
+ fixtureId: string;
117
+ label: string;
118
+ report: VoiceScenarioEvalReport;
119
+ status: VoiceEvalStatus;
120
+ };
121
+ export type VoiceScenarioFixtureEvalReport = {
122
+ checkedAt: number;
123
+ failed: number;
124
+ fixtures: VoiceScenarioFixtureEvalResult[];
125
+ passed: number;
126
+ status: VoiceEvalStatus;
127
+ total: number;
128
+ };
105
129
  export type VoiceEvalLink = {
106
130
  href: string;
107
131
  label: string;
@@ -111,6 +135,8 @@ export type VoiceEvalRoutesOptions = {
111
135
  baselineComparison?: VoiceEvalBaselineComparisonOptions;
112
136
  baselineStore?: VoiceEvalBaselineStore;
113
137
  events?: StoredVoiceTraceEvent[];
138
+ fixtures?: VoiceScenarioFixture[];
139
+ fixtureStore?: VoiceScenarioFixtureStore;
114
140
  headers?: HeadersInit;
115
141
  links?: VoiceEvalLink[];
116
142
  limit?: number;
@@ -132,8 +158,14 @@ export declare const runVoiceScenarioEvals: (options?: {
132
158
  scenarios?: VoiceScenarioEvalDefinition[];
133
159
  store?: VoiceTraceEventStore;
134
160
  }) => Promise<VoiceScenarioEvalReport>;
161
+ export declare const runVoiceScenarioFixtureEvals: (options?: {
162
+ fixtures?: VoiceScenarioFixture[];
163
+ fixtureStore?: VoiceScenarioFixtureStore;
164
+ scenarios?: VoiceScenarioEvalDefinition[];
165
+ }) => Promise<VoiceScenarioFixtureEvalReport>;
135
166
  export declare const compareVoiceEvalBaseline: (currentReport: VoiceEvalReport, baselineReport: VoiceEvalReport, options?: VoiceEvalBaselineComparisonOptions) => VoiceEvalBaselineComparison;
136
167
  export declare const createVoiceFileEvalBaselineStore: (filePath: string) => VoiceEvalBaselineStore;
168
+ export declare const createVoiceFileScenarioFixtureStore: (filePath: string) => VoiceScenarioFixtureStore;
137
169
  export declare const renderVoiceEvalHTML: (report: VoiceEvalReport, options?: {
138
170
  links?: VoiceEvalLink[];
139
171
  title?: string;
@@ -146,6 +178,10 @@ export declare const renderVoiceScenarioEvalHTML: (report: VoiceScenarioEvalRepo
146
178
  links?: VoiceEvalLink[];
147
179
  title?: string;
148
180
  }) => string;
181
+ export declare const renderVoiceScenarioFixtureEvalHTML: (report: VoiceScenarioFixtureEvalReport, options?: {
182
+ links?: VoiceEvalLink[];
183
+ title?: string;
184
+ }) => string;
149
185
  export declare const createVoiceEvalRoutes: (options: VoiceEvalRoutesOptions) => Elysia<"", {
150
186
  decorator: {};
151
187
  store: {};
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { voice } from './plugin';
2
2
  export { createVoiceAssistant, createVoiceExperiment, summarizeVoiceAssistantRuns } from './assistant';
3
3
  export { createVoiceAssistantHealthHTMLHandler, createVoiceAssistantHealthJSONHandler, createVoiceAssistantHealthRoutes, renderVoiceAssistantHealthHTML, summarizeVoiceAssistantHealth } from './assistantHealth';
4
4
  export { buildVoiceDiagnosticsMarkdown, createVoiceDiagnosticsRoutes, resolveVoiceDiagnosticsTraceFilter } from './diagnosticsRoutes';
5
- export { compareVoiceEvalBaseline, createVoiceFileEvalBaselineStore, createVoiceEvalRoutes, renderVoiceEvalBaselineHTML, renderVoiceEvalHTML, renderVoiceScenarioEvalHTML, runVoiceScenarioEvals, runVoiceSessionEvals } from './evalRoutes';
5
+ export { compareVoiceEvalBaseline, createVoiceFileEvalBaselineStore, createVoiceFileScenarioFixtureStore, createVoiceEvalRoutes, renderVoiceEvalBaselineHTML, renderVoiceEvalHTML, renderVoiceScenarioEvalHTML, renderVoiceScenarioFixtureEvalHTML, runVoiceScenarioEvals, runVoiceScenarioFixtureEvals, runVoiceSessionEvals } from './evalRoutes';
6
6
  export { createVoiceSessionListRoutes, createVoiceSessionReplayHTMLHandler, createVoiceSessionReplayJSONHandler, createVoiceSessionReplayRoutes, createVoiceSessionsHTMLHandler, createVoiceSessionsJSONHandler, renderVoiceSessionsHTML, summarizeVoiceSessions, summarizeVoiceSessionReplay } from './sessionReplay';
7
7
  export { createVoiceAgent, createVoiceAgentSquad, createVoiceAgentTool } from './agent';
8
8
  export { createStoredVoiceCallReviewArtifact, createStoredVoiceExternalObjectMap, createStoredVoiceIntegrationEvent, createStoredVoiceOpsTask, createVoiceFileExternalObjectMapStore, createVoiceFileAssistantMemoryStore, createVoiceFileIntegrationEventStore, createVoiceFileReviewStore, createVoiceFileRuntimeStorage, createVoiceFileSessionStore, createVoiceFileTaskStore, createVoiceFileTraceSinkDeliveryStore, createVoiceFileTraceEventStore } from './fileStore';
@@ -40,7 +40,7 @@ export type { VoiceAssistant, VoiceAssistantArtifactPlan, VoiceAssistantExperime
40
40
  export type { VoiceAssistantHealthFailure, VoiceAssistantHealthHTMLHandlerOptions, VoiceAssistantHealthRoutesOptions, VoiceAssistantHealthSummary, VoiceAssistantHealthSummaryOptions } from './assistantHealth';
41
41
  export type { VoiceAssistantMemoryBinding, VoiceAssistantMemoryHandle, VoiceAssistantMemoryOptions, VoiceAssistantMemoryRecord, VoiceAssistantMemoryStore } from './assistantMemory';
42
42
  export type { VoiceDiagnosticsRoutesOptions } from './diagnosticsRoutes';
43
- export type { VoiceEvalBaselineComparison, VoiceEvalBaselineComparisonOptions, VoiceEvalBaselineStore, VoiceEvalBaselineSummary, VoiceEvalLink, VoiceEvalReport, VoiceEvalRoutesOptions, VoiceEvalSessionReport, VoiceEvalStatus, VoiceEvalTrendBucket, VoiceScenarioEvalDefinition, VoiceScenarioEvalReport, VoiceScenarioEvalResult, VoiceScenarioEvalSessionResult } from './evalRoutes';
43
+ export type { VoiceEvalBaselineComparison, VoiceEvalBaselineComparisonOptions, VoiceEvalBaselineStore, VoiceEvalBaselineSummary, VoiceEvalLink, VoiceEvalReport, VoiceEvalRoutesOptions, VoiceEvalSessionReport, VoiceEvalStatus, VoiceEvalTrendBucket, VoiceScenarioEvalDefinition, VoiceScenarioEvalReport, VoiceScenarioEvalResult, VoiceScenarioEvalSessionResult, VoiceScenarioFixture, VoiceScenarioFixtureEvalReport, VoiceScenarioFixtureEvalResult, VoiceScenarioFixtureStore } from './evalRoutes';
44
44
  export type { VoiceSessionListHTMLHandlerOptions, VoiceSessionListItem, VoiceSessionListOptions, VoiceSessionListRoutesOptions, VoiceSessionListStatus, VoiceSessionReplay, VoiceSessionReplayHTMLHandlerOptions, VoiceSessionReplayOptions, VoiceSessionReplayRoutesOptions, VoiceSessionReplayTurn } from './sessionReplay';
45
45
  export type { AnthropicVoiceAssistantModelOptions, GeminiVoiceAssistantModelOptions, OpenAIVoiceAssistantModelOptions, VoiceProviderRouterEvent, VoiceProviderRouterFallbackMode, VoiceProviderRouterHealthOptions, VoiceProviderRouterOptions, VoiceProviderRouterPolicy, VoiceProviderRouterProviderHealth, VoiceProviderRouterProviderProfile, VoiceJSONAssistantModelHandler, VoiceJSONAssistantModelOptions } from './modelAdapters';
46
46
  export type { VoiceProviderHealthStatus, VoiceProviderHealthSummary, VoiceProviderHealthSummaryOptions } from './providerHealth';
package/dist/index.js CHANGED
@@ -8167,6 +8167,33 @@ var runVoiceScenarioEvals = async (options = {}) => {
8167
8167
  total: results.length
8168
8168
  };
8169
8169
  };
8170
+ var resolveScenarioFixtures = async (options) => [...options.fixtures ?? [], ...await options.fixtureStore?.list() ?? []];
8171
+ var runVoiceScenarioFixtureEvals = async (options = {}) => {
8172
+ const fixtures = await resolveScenarioFixtures(options);
8173
+ const results = await Promise.all(fixtures.map(async (fixture) => {
8174
+ const report = await runVoiceScenarioEvals({
8175
+ events: fixture.events,
8176
+ scenarios: options.scenarios
8177
+ });
8178
+ return {
8179
+ description: fixture.description,
8180
+ fixtureId: fixture.id,
8181
+ label: fixture.label ?? fixture.id,
8182
+ report,
8183
+ status: report.status
8184
+ };
8185
+ }));
8186
+ const failed = results.filter((fixture) => fixture.status === "fail").length;
8187
+ const passed = results.length - failed;
8188
+ return {
8189
+ checkedAt: Date.now(),
8190
+ failed,
8191
+ fixtures: results,
8192
+ passed,
8193
+ status: failed > 0 ? "fail" : "pass",
8194
+ total: results.length
8195
+ };
8196
+ };
8170
8197
  var summarizeEvalBaseline = (report) => {
8171
8198
  const failedSessionIds = report.sessions.filter((session) => session.status === "fail").map((session) => session.sessionId).sort();
8172
8199
  return {
@@ -8228,6 +8255,20 @@ var createVoiceFileEvalBaselineStore = (filePath) => ({
8228
8255
  await Bun.write(filePath, JSON.stringify(report, null, 2));
8229
8256
  }
8230
8257
  });
8258
+ var createVoiceFileScenarioFixtureStore = (filePath) => ({
8259
+ list: async () => {
8260
+ const file = Bun.file(filePath);
8261
+ if (!await file.exists()) {
8262
+ return [];
8263
+ }
8264
+ const text = await file.text();
8265
+ if (!text.trim()) {
8266
+ return [];
8267
+ }
8268
+ const parsed = JSON.parse(text);
8269
+ return Array.isArray(parsed) ? parsed : parsed.fixtures ?? [];
8270
+ }
8271
+ });
8231
8272
  var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
8232
8273
  var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
8233
8274
  var renderVoiceEvalHTML = (report, options = {}) => {
@@ -8258,6 +8299,15 @@ var renderVoiceScenarioEvalHTML = (report, options = {}) => {
8258
8299
  }).join("") : "<section><p>No scenarios configured.</p></section>";
8259
8300
  return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml9(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}.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}.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>${escapeHtml9(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>${scenarios}</main></body></html>`;
8260
8301
  };
8302
+ var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
8303
+ const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
8304
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml9(link.href)}">${escapeHtml9(link.label)}</a>`).join("")}</nav>` : "";
8305
+ const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
8306
+ const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml9(scenario.label)}</td><td>${escapeHtml9(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml9([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
8307
+ return `<section class="${fixture.status}"><h2>${escapeHtml9(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml9(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>`;
8308
+ }).join("") : "<section><p>No scenario fixtures configured.</p></section>";
8309
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml9(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}.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}.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>${escapeHtml9(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>${fixtures}</main></body></html>`;
8310
+ };
8261
8311
  var createVoiceEvalRoutes = (options) => {
8262
8312
  const path = options.path ?? "/evals";
8263
8313
  const routes = new Elysia7({
@@ -8279,6 +8329,11 @@ var createVoiceEvalRoutes = (options) => {
8279
8329
  scenarios: options.scenarios,
8280
8330
  store: options.store
8281
8331
  });
8332
+ const getFixtureReport = () => runVoiceScenarioFixtureEvals({
8333
+ fixtures: options.fixtures,
8334
+ fixtureStore: options.fixtureStore,
8335
+ scenarios: options.scenarios
8336
+ });
8282
8337
  routes.get(path, async () => {
8283
8338
  const report = await getReport();
8284
8339
  return new Response(renderVoiceEvalHTML(report, {
@@ -8366,6 +8421,26 @@ var createVoiceEvalRoutes = (options) => {
8366
8421
  }
8367
8422
  return report;
8368
8423
  });
8424
+ routes.get(`${path}/fixtures`, async () => {
8425
+ const report = await getFixtureReport();
8426
+ return new Response(renderVoiceScenarioFixtureEvalHTML(report, {
8427
+ links: options.links,
8428
+ title: `${options.title ?? "AbsoluteJS Voice Evals"} Fixtures`
8429
+ }), {
8430
+ headers: {
8431
+ "Content-Type": "text/html; charset=utf-8",
8432
+ ...options.headers
8433
+ }
8434
+ });
8435
+ });
8436
+ routes.get(`${path}/fixtures/json`, async () => getFixtureReport());
8437
+ routes.get(`${path}/fixtures/status`, async ({ set }) => {
8438
+ const report = await getFixtureReport();
8439
+ if (report.status === "fail") {
8440
+ set.status = 503;
8441
+ }
8442
+ return report;
8443
+ });
8369
8444
  return routes;
8370
8445
  };
8371
8446
  // src/sessionReplay.ts
@@ -13312,6 +13387,7 @@ export {
13312
13387
  shapeTelephonyAssistantText,
13313
13388
  selectVoiceTraceEventsForPrune,
13314
13389
  runVoiceSessionEvals,
13390
+ runVoiceScenarioFixtureEvals,
13315
13391
  runVoiceScenarioEvals,
13316
13392
  resolveVoiceTraceRedactionOptions,
13317
13393
  resolveVoiceSTTRoutingStrategy,
@@ -13330,6 +13406,7 @@ export {
13330
13406
  renderVoiceTraceMarkdown,
13331
13407
  renderVoiceTraceHTML,
13332
13408
  renderVoiceSessionsHTML,
13409
+ renderVoiceScenarioFixtureEvalHTML,
13333
13410
  renderVoiceScenarioEvalHTML,
13334
13411
  renderVoiceResilienceHTML,
13335
13412
  renderVoiceQualityHTML,
@@ -13455,6 +13532,7 @@ export {
13455
13532
  createVoiceFileTraceEventStore,
13456
13533
  createVoiceFileTaskStore,
13457
13534
  createVoiceFileSessionStore,
13535
+ createVoiceFileScenarioFixtureStore,
13458
13536
  createVoiceFileRuntimeStorage,
13459
13537
  createVoiceFileReviewStore,
13460
13538
  createVoiceFileIntegrationEventStore,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.44",
3
+ "version": "0.0.22-beta.45",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",