@absolutejs/voice 0.0.22-beta.184 → 0.0.22-beta.186

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.
@@ -2,13 +2,15 @@ import type { VoiceCampaignStore } from './campaign';
2
2
  import { type VoiceAuditActor, type VoiceAuditEventStore } from './audit';
3
3
  import type { VoiceAuditSinkDeliveryStore } from './auditSinks';
4
4
  import type { VoiceIntegrationEventStore, VoiceOpsTaskStore } from './ops';
5
+ import type { VoiceIncidentBundleStore } from './incidentBundle';
5
6
  import type { VoiceCallReviewStore } from './testing/review';
6
7
  import type { VoiceTraceEventStore, VoiceTracePruneFilter, VoiceTraceSinkDeliveryStore } from './trace';
7
8
  import type { VoiceSessionStore } from './types';
8
- export type VoiceDataRetentionScope = 'auditDeliveries' | 'campaigns' | 'events' | 'reviews' | 'sessions' | 'tasks' | 'traceDeliveries' | 'traces';
9
+ export type VoiceDataRetentionScope = 'auditDeliveries' | 'campaigns' | 'events' | 'incidentBundles' | 'reviews' | 'sessions' | 'tasks' | 'traceDeliveries' | 'traces';
9
10
  export type VoiceDataRetentionStores = {
10
11
  campaigns?: VoiceCampaignStore;
11
12
  events?: VoiceIntegrationEventStore;
13
+ incidentBundles?: VoiceIncidentBundleStore;
12
14
  reviews?: VoiceCallReviewStore;
13
15
  session?: VoiceSessionStore;
14
16
  sessions?: VoiceSessionStore;
@@ -2,6 +2,7 @@ import { type StoredVoiceAuditEvent, type VoiceAuditEventStore } from './audit';
2
2
  import type { VoiceAuditSinkDeliveryRecord, VoiceAuditSinkDeliveryStore } from './auditSinks';
3
3
  import type { VoiceCampaignStore } from './campaign';
4
4
  import { type VoiceAssistantMemoryRecord, type VoiceAssistantMemoryStore } from './assistantMemory';
5
+ import type { StoredVoiceIncidentBundleArtifact, VoiceIncidentBundleStore } from './incidentBundle';
5
6
  import { type StoredVoiceTraceEvent, type VoiceTraceSinkDeliveryRecord, type VoiceTraceSinkDeliveryStore, type VoiceTraceEventStore } from './trace';
6
7
  import type { StoredVoiceIntegrationEvent, StoredVoiceExternalObjectMap, StoredVoiceOpsTask, VoiceExternalObjectMap, VoiceExternalObjectMapStore, VoiceIntegrationEvent, VoiceIntegrationEventStore, VoiceOpsTask, VoiceOpsTaskStore } from './ops';
7
8
  import type { StoredVoiceCallReviewArtifact, VoiceCallReviewArtifact, VoiceCallReviewStore } from './testing/review';
@@ -10,12 +11,13 @@ export type VoiceFileStoreOptions = {
10
11
  directory: string;
11
12
  pretty?: boolean;
12
13
  };
13
- export type VoiceFileRuntimeStorage<TSession extends VoiceSessionRecord = VoiceSessionRecord, TReview extends StoredVoiceCallReviewArtifact = StoredVoiceCallReviewArtifact, TTask extends StoredVoiceOpsTask = StoredVoiceOpsTask, TEvent extends StoredVoiceIntegrationEvent = StoredVoiceIntegrationEvent, TMapping extends StoredVoiceExternalObjectMap = StoredVoiceExternalObjectMap, TTrace extends StoredVoiceTraceEvent = StoredVoiceTraceEvent, TTraceDelivery extends VoiceTraceSinkDeliveryRecord = VoiceTraceSinkDeliveryRecord, TAudit extends StoredVoiceAuditEvent = StoredVoiceAuditEvent, TAuditDelivery extends VoiceAuditSinkDeliveryRecord = VoiceAuditSinkDeliveryRecord, TMemory extends VoiceAssistantMemoryRecord = VoiceAssistantMemoryRecord> = {
14
+ export type VoiceFileRuntimeStorage<TSession extends VoiceSessionRecord = VoiceSessionRecord, TReview extends StoredVoiceCallReviewArtifact = StoredVoiceCallReviewArtifact, TTask extends StoredVoiceOpsTask = StoredVoiceOpsTask, TEvent extends StoredVoiceIntegrationEvent = StoredVoiceIntegrationEvent, TMapping extends StoredVoiceExternalObjectMap = StoredVoiceExternalObjectMap, TTrace extends StoredVoiceTraceEvent = StoredVoiceTraceEvent, TTraceDelivery extends VoiceTraceSinkDeliveryRecord = VoiceTraceSinkDeliveryRecord, TAudit extends StoredVoiceAuditEvent = StoredVoiceAuditEvent, TAuditDelivery extends VoiceAuditSinkDeliveryRecord = VoiceAuditSinkDeliveryRecord, TIncident extends StoredVoiceIncidentBundleArtifact = StoredVoiceIncidentBundleArtifact, TMemory extends VoiceAssistantMemoryRecord = VoiceAssistantMemoryRecord> = {
14
15
  audit: VoiceAuditEventStore<TAudit>;
15
16
  auditDeliveries: VoiceAuditSinkDeliveryStore<TAuditDelivery>;
16
17
  campaigns: VoiceCampaignStore;
17
18
  events: VoiceIntegrationEventStore<TEvent>;
18
19
  externalObjects: VoiceExternalObjectMapStore<TMapping>;
20
+ incidentBundles: VoiceIncidentBundleStore<TIncident>;
19
21
  memories: VoiceAssistantMemoryStore<TMemory>;
20
22
  reviews: VoiceCallReviewStore<TReview>;
21
23
  session: VoiceSessionStore<TSession>;
@@ -34,7 +36,8 @@ export declare const createVoiceFileTraceSinkDeliveryStore: <TDelivery extends V
34
36
  export declare const createVoiceFileAuditEventStore: <TEvent extends StoredVoiceAuditEvent = StoredVoiceAuditEvent>(options: VoiceFileStoreOptions) => VoiceAuditEventStore<TEvent>;
35
37
  export declare const createVoiceFileAuditSinkDeliveryStore: <TDelivery extends VoiceAuditSinkDeliveryRecord = VoiceAuditSinkDeliveryRecord>(options: VoiceFileStoreOptions) => VoiceAuditSinkDeliveryStore<TDelivery>;
36
38
  export declare const createVoiceFileAssistantMemoryStore: <TRecord extends VoiceAssistantMemoryRecord = VoiceAssistantMemoryRecord>(options: VoiceFileStoreOptions) => VoiceAssistantMemoryStore<TRecord>;
37
- export declare const createVoiceFileRuntimeStorage: <TSession extends VoiceSessionRecord = VoiceSessionRecord, TReview extends StoredVoiceCallReviewArtifact = StoredVoiceCallReviewArtifact, TTask extends StoredVoiceOpsTask = StoredVoiceOpsTask, TEvent extends StoredVoiceIntegrationEvent = StoredVoiceIntegrationEvent, TMapping extends StoredVoiceExternalObjectMap = StoredVoiceExternalObjectMap, TTrace extends StoredVoiceTraceEvent = StoredVoiceTraceEvent, TTraceDelivery extends VoiceTraceSinkDeliveryRecord = VoiceTraceSinkDeliveryRecord, TAudit extends StoredVoiceAuditEvent = StoredVoiceAuditEvent, TAuditDelivery extends VoiceAuditSinkDeliveryRecord = VoiceAuditSinkDeliveryRecord, TMemory extends VoiceAssistantMemoryRecord = VoiceAssistantMemoryRecord>(options: VoiceFileStoreOptions) => VoiceFileRuntimeStorage<TSession, TReview, TTask, TEvent, TMapping, TTrace, TTraceDelivery, TAudit, TAuditDelivery, TMemory>;
39
+ export declare const createVoiceFileIncidentBundleStore: <TArtifact extends StoredVoiceIncidentBundleArtifact = StoredVoiceIncidentBundleArtifact>(options: VoiceFileStoreOptions) => VoiceIncidentBundleStore<TArtifact>;
40
+ export declare const createVoiceFileRuntimeStorage: <TSession extends VoiceSessionRecord = VoiceSessionRecord, TReview extends StoredVoiceCallReviewArtifact = StoredVoiceCallReviewArtifact, TTask extends StoredVoiceOpsTask = StoredVoiceOpsTask, TEvent extends StoredVoiceIntegrationEvent = StoredVoiceIntegrationEvent, TMapping extends StoredVoiceExternalObjectMap = StoredVoiceExternalObjectMap, TTrace extends StoredVoiceTraceEvent = StoredVoiceTraceEvent, TTraceDelivery extends VoiceTraceSinkDeliveryRecord = VoiceTraceSinkDeliveryRecord, TAudit extends StoredVoiceAuditEvent = StoredVoiceAuditEvent, TAuditDelivery extends VoiceAuditSinkDeliveryRecord = VoiceAuditSinkDeliveryRecord, TIncident extends StoredVoiceIncidentBundleArtifact = StoredVoiceIncidentBundleArtifact, TMemory extends VoiceAssistantMemoryRecord = VoiceAssistantMemoryRecord>(options: VoiceFileStoreOptions) => VoiceFileRuntimeStorage<TSession, TReview, TTask, TEvent, TMapping, TTrace, TTraceDelivery, TAudit, TAuditDelivery, TIncident, TMemory>;
38
41
  export declare const createStoredVoiceCallReviewArtifact: <TArtifact extends VoiceCallReviewArtifact = VoiceCallReviewArtifact>(id: string, artifact: TArtifact) => TArtifact & {
39
42
  id: string;
40
43
  };
@@ -0,0 +1,116 @@
1
+ import { Elysia } from 'elysia';
2
+ import { type VoiceOperationsRecord, type VoiceOperationsRecordOptions } from './operationsRecord';
3
+ import { type VoiceTraceRedactionConfig } from './trace';
4
+ export type VoiceIncidentBundleFormat = 'json' | 'markdown';
5
+ export type VoiceIncidentBundle = {
6
+ auditMarkdown?: string;
7
+ exportedAt: number;
8
+ formatVersion: 1;
9
+ markdown: string;
10
+ record: VoiceOperationsRecord;
11
+ redacted: boolean;
12
+ sessionId: string;
13
+ summary: VoiceIncidentBundleSummary;
14
+ traceMarkdown: string;
15
+ };
16
+ export type StoredVoiceIncidentBundleArtifact = {
17
+ bundle: VoiceIncidentBundle;
18
+ createdAt: number;
19
+ expiresAt?: number;
20
+ id: string;
21
+ metadata?: Record<string, unknown>;
22
+ redacted: boolean;
23
+ sessionId: string;
24
+ };
25
+ export type VoiceIncidentBundleStoreFilter = {
26
+ expiredAt?: number;
27
+ sessionId?: string;
28
+ };
29
+ export type VoiceIncidentBundleStore<TArtifact extends StoredVoiceIncidentBundleArtifact = StoredVoiceIncidentBundleArtifact> = {
30
+ get: (id: string) => Promise<TArtifact | undefined> | TArtifact | undefined;
31
+ list: (filter?: VoiceIncidentBundleStoreFilter) => Promise<TArtifact[]> | TArtifact[];
32
+ remove: (id: string) => Promise<void> | void;
33
+ set: (id: string, artifact: TArtifact) => Promise<void> | void;
34
+ };
35
+ export type VoiceIncidentBundleSummary = {
36
+ auditEvents: number;
37
+ durationMs?: number;
38
+ errors: number;
39
+ handoffs: number;
40
+ providers: string[];
41
+ sessionId: string;
42
+ status: VoiceOperationsRecord['status'];
43
+ tools: number;
44
+ traceEvents: number;
45
+ turns: number;
46
+ };
47
+ export type VoiceIncidentBundleOptions = VoiceOperationsRecordOptions & {
48
+ redact?: VoiceTraceRedactionConfig;
49
+ title?: string;
50
+ };
51
+ export type VoiceIncidentBundleRoutesOptions = Omit<VoiceIncidentBundleOptions, 'sessionId'> & {
52
+ headers?: HeadersInit;
53
+ markdownPath?: false | string;
54
+ name?: string;
55
+ path?: string;
56
+ };
57
+ export type VoiceIncidentBundleArtifactOptions = {
58
+ createdAt?: number;
59
+ expiresAt?: number;
60
+ id?: string;
61
+ metadata?: Record<string, unknown>;
62
+ ttlMs?: number;
63
+ };
64
+ export type VoiceIncidentBundleRetentionOptions = {
65
+ before?: number;
66
+ beforeOrAt?: number;
67
+ dryRun?: boolean;
68
+ expiredAt?: number;
69
+ keepNewest?: number;
70
+ limit?: number;
71
+ store: VoiceIncidentBundleStore;
72
+ };
73
+ export type VoiceIncidentBundleRetentionReport = {
74
+ deleted: StoredVoiceIncidentBundleArtifact[];
75
+ deletedCount: number;
76
+ deletedIds: string[];
77
+ dryRun: boolean;
78
+ scannedCount: number;
79
+ };
80
+ export declare const createVoiceMemoryIncidentBundleStore: <TArtifact extends StoredVoiceIncidentBundleArtifact = StoredVoiceIncidentBundleArtifact>() => VoiceIncidentBundleStore<TArtifact>;
81
+ export declare const createStoredVoiceIncidentBundleArtifact: (bundle: VoiceIncidentBundle, options?: VoiceIncidentBundleArtifactOptions) => StoredVoiceIncidentBundleArtifact;
82
+ export declare const saveVoiceIncidentBundleArtifact: (input: {
83
+ bundle: VoiceIncidentBundle;
84
+ options?: VoiceIncidentBundleArtifactOptions;
85
+ store: VoiceIncidentBundleStore;
86
+ }) => Promise<StoredVoiceIncidentBundleArtifact>;
87
+ export declare const pruneVoiceIncidentBundleArtifacts: (options: VoiceIncidentBundleRetentionOptions) => Promise<VoiceIncidentBundleRetentionReport>;
88
+ export declare const buildVoiceIncidentBundle: (options: VoiceIncidentBundleOptions) => Promise<VoiceIncidentBundle>;
89
+ export declare const createVoiceIncidentBundleRoutes: (options: VoiceIncidentBundleRoutesOptions) => Elysia<"", {
90
+ decorator: {};
91
+ store: {};
92
+ derive: {};
93
+ resolve: {};
94
+ }, {
95
+ typebox: {};
96
+ error: {};
97
+ }, {
98
+ schema: {};
99
+ standaloneSchema: {};
100
+ macro: {};
101
+ macroFn: {};
102
+ parser: {};
103
+ response: {};
104
+ }, {}, {
105
+ derive: {};
106
+ resolve: {};
107
+ schema: {};
108
+ standaloneSchema: {};
109
+ response: {};
110
+ }, {
111
+ derive: {};
112
+ resolve: {};
113
+ schema: {};
114
+ standaloneSchema: {};
115
+ response: {};
116
+ }>;
package/dist/index.d.ts CHANGED
@@ -35,7 +35,7 @@ export { createVoiceTurnQualityHTMLHandler, createVoiceTurnQualityJSONHandler, c
35
35
  export { createVoiceOutcomeContractHTMLHandler, createVoiceOutcomeContractJSONHandler, createVoiceOutcomeContractRoutes, renderVoiceOutcomeContractHTML, runVoiceOutcomeContractSuite } from './outcomeContract';
36
36
  export { applyVoiceTelephonyOutcome, createMemoryVoiceTelephonyWebhookIdempotencyStore, createVoiceTelephonyOutcomePolicy, createVoiceTelephonyWebhookHandler, createVoiceTelephonyWebhookRoutes, parseVoiceTelephonyWebhookEvent, resolveVoiceTelephonyOutcome, signVoiceTwilioWebhook, verifyVoiceTwilioWebhookSignature, voiceTelephonyOutcomeToRouteResult } from './telephonyOutcome';
37
37
  export { createVoicePhoneAgent } from './phoneAgent';
38
- export { createStoredVoiceCallReviewArtifact, createStoredVoiceExternalObjectMap, createStoredVoiceIntegrationEvent, createStoredVoiceOpsTask, createVoiceFileExternalObjectMapStore, createVoiceFileAssistantMemoryStore, createVoiceFileAuditEventStore, createVoiceFileAuditSinkDeliveryStore, createVoiceFileCampaignStore, createVoiceFileIntegrationEventStore, createVoiceFileReviewStore, createVoiceFileRuntimeStorage, createVoiceFileSessionStore, createVoiceFileTaskStore, createVoiceFileTraceSinkDeliveryStore, createVoiceFileTraceEventStore } from './fileStore';
38
+ export { createStoredVoiceCallReviewArtifact, createStoredVoiceExternalObjectMap, createStoredVoiceIntegrationEvent, createStoredVoiceOpsTask, createVoiceFileIncidentBundleStore, createVoiceFileExternalObjectMapStore, createVoiceFileAssistantMemoryStore, createVoiceFileAuditEventStore, createVoiceFileAuditSinkDeliveryStore, createVoiceFileCampaignStore, createVoiceFileIntegrationEventStore, createVoiceFileReviewStore, createVoiceFileRuntimeStorage, createVoiceFileSessionStore, createVoiceFileTaskStore, createVoiceFileTraceSinkDeliveryStore, createVoiceFileTraceEventStore } from './fileStore';
39
39
  export { createVoiceAssistantMemoryHandle, createVoiceAssistantMemoryRecord, createVoiceMemoryAssistantMemoryStore, resolveVoiceAssistantMemoryNamespace } from './assistantMemory';
40
40
  export { createAnthropicVoiceAssistantModel, createGeminiVoiceAssistantModel, createJSONVoiceAssistantModel, createOpenAIVoiceAssistantModel, resolveVoiceProviderRoutingPolicyPreset, createVoiceProviderRouter } from './modelAdapters';
41
41
  export { createOpenAIRealtimeAdapter } from './openaiRealtime';
@@ -49,6 +49,7 @@ export { createVoiceReadinessProfile, recommendVoiceReadinessProfile } from './r
49
49
  export { buildVoiceProviderContractMatrix, createVoiceProviderContractMatrixHTMLHandler, createVoiceProviderContractMatrixJSONHandler, createVoiceProviderContractMatrixPreset, createVoiceProviderContractMatrixRoutes, evaluateVoiceProviderStackGaps, renderVoiceProviderContractMatrixHTML, recommendVoiceProviderStack } from './providerStackRecommendations';
50
50
  export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
51
51
  export { buildVoiceOperationsRecord, createVoiceOperationsRecordRoutes, renderVoiceOperationsRecordHTML } from './operationsRecord';
52
+ export { buildVoiceIncidentBundle, createStoredVoiceIncidentBundleArtifact, createVoiceIncidentBundleRoutes, createVoiceMemoryIncidentBundleStore, pruneVoiceIncidentBundleArtifacts, saveVoiceIncidentBundleArtifact } from './incidentBundle';
52
53
  export { summarizeVoiceOpsStatus } from './opsStatus';
53
54
  export { createVoiceOpsStatusRoutes, renderVoiceOpsStatusHTML } from './opsStatusRoutes';
54
55
  export { createVoiceQualityRoutes, evaluateVoiceQuality, renderVoiceQualityHTML } from './qualityRoutes';
@@ -109,6 +110,7 @@ export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptio
109
110
  export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
110
111
  export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderContractCheck, VoiceProviderContractCheckStatus, VoiceProviderContractDefinition, VoiceProviderContractMatrixHandlerOptions, VoiceProviderContractMatrixHTMLHandlerOptions, VoiceProviderContractMatrixInput, VoiceProviderContractMatrixPresetOptions, VoiceProviderContractMatrixReport, VoiceProviderContractMatrixRoutesOptions, VoiceProviderContractMatrixRow, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
111
112
  export type { VoiceOperationsRecord, VoiceOperationsRecordAgentHandoff, VoiceOperationsRecordAuditSummary, VoiceOperationsRecordOptions, VoiceOperationsRecordOutcome, VoiceOperationsRecordRoutesOptions, VoiceOperationsRecordStatus, VoiceOperationsRecordTool } from './operationsRecord';
113
+ export type { StoredVoiceIncidentBundleArtifact, VoiceIncidentBundle, VoiceIncidentBundleArtifactOptions, VoiceIncidentBundleFormat, VoiceIncidentBundleOptions, VoiceIncidentBundleRetentionOptions, VoiceIncidentBundleRetentionReport, VoiceIncidentBundleRoutesOptions, VoiceIncidentBundleStore, VoiceIncidentBundleStoreFilter, VoiceIncidentBundleSummary } from './incidentBundle';
112
114
  export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
113
115
  export type { VoiceResilienceIOSimulator, VoiceResilienceLink, VoiceResiliencePageData, VoiceResilienceRoutesOptions, VoiceResilienceSimulationProvider, VoiceRoutingKindSummary, VoiceRoutingDecisionSummary, VoiceRoutingDecisionSummaryOptions, VoiceRoutingEvent, VoiceRoutingEventKind, VoiceRoutingSessionSummary, VoiceRoutingSessionSummaryOptions } from './resilienceRoutes';
114
116
  export type { VoiceIOProviderRouterEvent, VoiceIOProviderRouterOptions, VoiceIOProviderRouterPolicy, VoiceIOProviderRouterPolicyConfig, VoiceSTTProviderRouterOptions, VoiceTTSProviderRouterOptions } from './providerAdapters';
package/dist/index.js CHANGED
@@ -12063,6 +12063,7 @@ var allRetentionScopes = [
12063
12063
  "auditDeliveries",
12064
12064
  "campaigns",
12065
12065
  "events",
12066
+ "incidentBundles",
12066
12067
  "reviews",
12067
12068
  "sessions",
12068
12069
  "tasks",
@@ -12123,6 +12124,10 @@ var getEventRetentionRecord = (record) => ({
12123
12124
  at: record.createdAt,
12124
12125
  id: record.id
12125
12126
  });
12127
+ var getIncidentBundleRetentionRecord = (record) => ({
12128
+ at: record.expiresAt ?? record.createdAt,
12129
+ id: record.id
12130
+ });
12126
12131
  var getReviewRetentionRecord = (record) => ({
12127
12132
  at: record.generatedAt ?? 0,
12128
12133
  id: record.id
@@ -12215,6 +12220,13 @@ var applyVoiceDataRetentionPolicy = async (options) => {
12215
12220
  toRecord: getEventRetentionRecord
12216
12221
  }) : reportSkippedScope(scope, dryRun, "missing-store");
12217
12222
  }
12223
+ if (scope === "incidentBundles") {
12224
+ return options.incidentBundles ? runRetentionScope({
12225
+ ...common,
12226
+ store: options.incidentBundles,
12227
+ toRecord: getIncidentBundleRetentionRecord
12228
+ }) : reportSkippedScope(scope, dryRun, "missing-store");
12229
+ }
12218
12230
  if (scope === "reviews") {
12219
12231
  return options.reviews ? runRetentionScope({
12220
12232
  ...common,
@@ -18265,6 +18277,44 @@ var createVoiceFileAssistantMemoryStore = (options) => {
18265
18277
  };
18266
18278
  return { delete: remove, get, list, set };
18267
18279
  };
18280
+ var createVoiceFileIncidentBundleStore = (options) => {
18281
+ const get = async (id) => {
18282
+ const path = resolveFilePath(options.directory, id);
18283
+ try {
18284
+ return await readJsonFile(path);
18285
+ } catch (error) {
18286
+ if (error.code === "ENOENT") {
18287
+ return;
18288
+ }
18289
+ throw error;
18290
+ }
18291
+ };
18292
+ const list = async (filter = {}) => {
18293
+ const files = await listJsonFiles(options.directory);
18294
+ const artifacts = await Promise.all(files.map((file) => readJsonFile(file)));
18295
+ return artifacts.filter((artifact) => {
18296
+ if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
18297
+ return false;
18298
+ }
18299
+ if (typeof filter.expiredAt === "number" && (artifact.expiresAt === undefined || artifact.expiresAt > filter.expiredAt)) {
18300
+ return false;
18301
+ }
18302
+ return true;
18303
+ }).sort((left, right) => right.createdAt - left.createdAt || left.id.localeCompare(right.id));
18304
+ };
18305
+ const set = async (id, artifact) => {
18306
+ await writeJsonFile(resolveFilePath(options.directory, id), {
18307
+ ...artifact,
18308
+ id
18309
+ }, options);
18310
+ };
18311
+ const remove = async (id) => {
18312
+ await rm(resolveFilePath(options.directory, id), {
18313
+ force: true
18314
+ });
18315
+ };
18316
+ return { get, list, remove, set };
18317
+ };
18268
18318
  var createVoiceFileRuntimeStorage = (options) => ({
18269
18319
  audit: createVoiceFileAuditEventStore({
18270
18320
  ...options,
@@ -18286,6 +18336,10 @@ var createVoiceFileRuntimeStorage = (options) => ({
18286
18336
  ...options,
18287
18337
  directory: join2(options.directory, "external-objects")
18288
18338
  }),
18339
+ incidentBundles: createVoiceFileIncidentBundleStore({
18340
+ ...options,
18341
+ directory: join2(options.directory, "incident-bundles")
18342
+ }),
18289
18343
  memories: createVoiceFileAssistantMemoryStore({
18290
18344
  ...options,
18291
18345
  directory: join2(options.directory, "memories")
@@ -22644,6 +22698,235 @@ var createVoiceOperationsRecordRoutes = (options) => {
22644
22698
  }
22645
22699
  return routes;
22646
22700
  };
22701
+ // src/incidentBundle.ts
22702
+ import { Elysia as Elysia38 } from "elysia";
22703
+ var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
22704
+ if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
22705
+ return false;
22706
+ }
22707
+ if (typeof filter.expiredAt === "number" && (artifact.expiresAt === undefined || artifact.expiresAt > filter.expiredAt)) {
22708
+ return false;
22709
+ }
22710
+ return true;
22711
+ }).sort((left, right) => right.createdAt - left.createdAt || left.id.localeCompare(right.id));
22712
+ var createVoiceMemoryIncidentBundleStore = () => {
22713
+ const artifacts = new Map;
22714
+ return {
22715
+ get: (id) => artifacts.get(id),
22716
+ list: (filter) => filterIncidentBundleArtifacts([...artifacts.values()], filter),
22717
+ remove: (id) => {
22718
+ artifacts.delete(id);
22719
+ },
22720
+ set: (id, artifact) => {
22721
+ artifacts.set(id, {
22722
+ ...artifact,
22723
+ id
22724
+ });
22725
+ }
22726
+ };
22727
+ };
22728
+ var createStoredVoiceIncidentBundleArtifact = (bundle, options = {}) => {
22729
+ const createdAt = options.createdAt ?? Date.now();
22730
+ return {
22731
+ bundle,
22732
+ createdAt,
22733
+ expiresAt: options.expiresAt ?? (typeof options.ttlMs === "number" ? createdAt + options.ttlMs : undefined),
22734
+ id: options.id ?? `voice-incident:${bundle.sessionId}:${bundle.exportedAt}:${crypto.randomUUID()}`,
22735
+ metadata: options.metadata,
22736
+ redacted: bundle.redacted,
22737
+ sessionId: bundle.sessionId
22738
+ };
22739
+ };
22740
+ var saveVoiceIncidentBundleArtifact = async (input) => {
22741
+ const artifact = createStoredVoiceIncidentBundleArtifact(input.bundle, input.options);
22742
+ await input.store.set(artifact.id, artifact);
22743
+ return artifact;
22744
+ };
22745
+ var retentionTimeMatch = (artifact, options) => {
22746
+ if (typeof options.expiredAt === "number" && (artifact.expiresAt === undefined || artifact.expiresAt > options.expiredAt)) {
22747
+ return false;
22748
+ }
22749
+ if (typeof options.before === "number" && artifact.createdAt >= options.before) {
22750
+ return false;
22751
+ }
22752
+ if (typeof options.beforeOrAt === "number" && artifact.createdAt > options.beforeOrAt) {
22753
+ return false;
22754
+ }
22755
+ return true;
22756
+ };
22757
+ var pruneVoiceIncidentBundleArtifacts = async (options) => {
22758
+ const dryRun = Boolean(options.dryRun);
22759
+ const artifacts = await options.store.list();
22760
+ let selected = artifacts.filter((artifact) => retentionTimeMatch(artifact, options)).sort((left, right) => left.createdAt - right.createdAt || left.id.localeCompare(right.id));
22761
+ if (typeof options.keepNewest === "number" && options.keepNewest >= 0) {
22762
+ const newest = new Set([...selected].sort((left, right) => right.createdAt - left.createdAt || right.id.localeCompare(left.id)).slice(0, options.keepNewest).map((artifact) => artifact.id));
22763
+ selected = selected.filter((artifact) => !newest.has(artifact.id));
22764
+ }
22765
+ if (typeof options.limit === "number" && options.limit >= 0) {
22766
+ selected = selected.slice(0, options.limit);
22767
+ }
22768
+ if (!dryRun) {
22769
+ await Promise.all(selected.map((artifact) => options.store.remove(artifact.id)));
22770
+ }
22771
+ return {
22772
+ deleted: selected,
22773
+ deletedCount: selected.length,
22774
+ deletedIds: selected.map((artifact) => artifact.id),
22775
+ dryRun,
22776
+ scannedCount: artifacts.length
22777
+ };
22778
+ };
22779
+ var buildSummary = (record) => ({
22780
+ auditEvents: record.audit?.total ?? 0,
22781
+ durationMs: record.summary.callDurationMs,
22782
+ errors: record.summary.errorCount,
22783
+ handoffs: record.handoffs.length,
22784
+ providers: record.providers.map((provider) => provider.provider),
22785
+ sessionId: record.sessionId,
22786
+ status: record.status,
22787
+ tools: record.tools.length,
22788
+ traceEvents: record.traceEvents.length,
22789
+ turns: record.summary.turnCount
22790
+ });
22791
+ var renderIncidentMarkdown = (input) => {
22792
+ const lines = [
22793
+ `# ${input.title ?? `Voice Incident ${input.summary.sessionId}`}`,
22794
+ "",
22795
+ `Session: ${input.summary.sessionId}`,
22796
+ `Status: ${input.summary.status}`,
22797
+ `Trace events: ${input.summary.traceEvents}`,
22798
+ `Audit events: ${input.summary.auditEvents}`,
22799
+ `Turns: ${input.summary.turns}`,
22800
+ `Errors: ${input.summary.errors}`,
22801
+ `Handoffs: ${input.summary.handoffs}`,
22802
+ `Tools: ${input.summary.tools}`,
22803
+ `Providers: ${input.summary.providers.join(", ") || "none"}`,
22804
+ input.summary.durationMs === undefined ? undefined : `Duration: ${input.summary.durationMs}ms`,
22805
+ "",
22806
+ "## Outcome",
22807
+ "",
22808
+ `- Assistant replies: ${input.record.outcome.assistantReplies}`,
22809
+ `- Complete: ${input.record.outcome.complete ? "yes" : "no"}`,
22810
+ `- Escalated: ${input.record.outcome.escalated ? "yes" : "no"}`,
22811
+ `- Transferred: ${input.record.outcome.transferred ? "yes" : "no"}`,
22812
+ `- Voicemail: ${input.record.outcome.voicemail ? "yes" : "no"}`,
22813
+ `- No answer: ${input.record.outcome.noAnswer ? "yes" : "no"}`,
22814
+ "",
22815
+ "## Handoffs",
22816
+ "",
22817
+ ...input.record.handoffs.length ? input.record.handoffs.map((handoff) => `- ${handoff.fromAgentId ?? "unknown"} -> ${handoff.targetAgentId ?? "unknown"} ${handoff.status ?? ""} ${handoff.summary ?? handoff.reason ?? ""}`.trim()) : ["- none"],
22818
+ "",
22819
+ "## Tools",
22820
+ "",
22821
+ ...input.record.tools.length ? input.record.tools.map((tool) => `- ${tool.toolName ?? "tool"} ${tool.status ?? ""} ${tool.elapsedMs === undefined ? "" : `${tool.elapsedMs}ms`} ${tool.error ?? ""}`.trim()) : ["- none"],
22822
+ "",
22823
+ "## Trace Evidence",
22824
+ "",
22825
+ input.traceMarkdown,
22826
+ ""
22827
+ ].filter((line) => line !== undefined);
22828
+ if (input.auditMarkdown) {
22829
+ lines.push("## Audit Evidence", "", input.auditMarkdown);
22830
+ }
22831
+ return lines.join(`
22832
+ `);
22833
+ };
22834
+ var redactRecordValue = (value, redactedEvents, redact) => {
22835
+ if (!redact) {
22836
+ return value;
22837
+ }
22838
+ if (Array.isArray(value)) {
22839
+ return value.map((item) => redactRecordValue(item, redactedEvents, redact));
22840
+ }
22841
+ if (typeof value === "string") {
22842
+ return redactVoiceTraceText(value, redact);
22843
+ }
22844
+ if (typeof value === "object" && value) {
22845
+ return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [
22846
+ key,
22847
+ key === "events" || key === "traceEvents" ? redactedEvents : redactRecordValue(entryValue, redactedEvents, redact)
22848
+ ]));
22849
+ }
22850
+ return value;
22851
+ };
22852
+ var redactOperationsRecord = (record, input) => ({
22853
+ ...redactRecordValue(record, input.traceEvents, input.redact),
22854
+ audit: record.audit ? {
22855
+ ...record.audit,
22856
+ events: input.auditEvents ?? []
22857
+ } : undefined,
22858
+ traceEvents: input.traceEvents
22859
+ });
22860
+ var buildVoiceIncidentBundle = async (options) => {
22861
+ const record = await buildVoiceOperationsRecord(options);
22862
+ const redactedTraceEvents = options.redact ? redactVoiceTraceEvents(record.traceEvents, options.redact) : record.traceEvents;
22863
+ const redactedAuditEvents = options.redact && record.audit ? redactVoiceAuditEvents(record.audit.events, options.redact) : record.audit?.events;
22864
+ const redactedRecord = redactOperationsRecord(record, {
22865
+ auditEvents: redactedAuditEvents,
22866
+ redact: options.redact,
22867
+ traceEvents: redactedTraceEvents
22868
+ });
22869
+ const summary = buildSummary(redactedRecord);
22870
+ const traceMarkdown = renderVoiceTraceMarkdown(record.traceEvents, {
22871
+ evaluation: options.evaluation,
22872
+ redact: options.redact,
22873
+ title: `Voice Incident Trace ${options.sessionId}`
22874
+ });
22875
+ const auditMarkdown = record.audit ? renderVoiceAuditMarkdown(record.audit.events, {
22876
+ redact: options.redact,
22877
+ title: `Voice Incident Audit ${options.sessionId}`
22878
+ }) : undefined;
22879
+ const markdown = renderIncidentMarkdown({
22880
+ auditMarkdown,
22881
+ record: redactedRecord,
22882
+ summary,
22883
+ title: options.title,
22884
+ traceMarkdown
22885
+ });
22886
+ return {
22887
+ auditMarkdown,
22888
+ exportedAt: Date.now(),
22889
+ formatVersion: 1,
22890
+ markdown,
22891
+ record: redactedRecord,
22892
+ redacted: Boolean(options.redact),
22893
+ sessionId: options.sessionId,
22894
+ summary,
22895
+ traceMarkdown
22896
+ };
22897
+ };
22898
+ var createVoiceIncidentBundleRoutes = (options) => {
22899
+ const path = options.path ?? "/api/voice-incidents/:sessionId";
22900
+ const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
22901
+ const routes = new Elysia38({
22902
+ name: options.name ?? "absolutejs-voice-incident-bundle"
22903
+ });
22904
+ const getSessionId = (params) => params.sessionId ?? "";
22905
+ const buildBundle = (sessionId) => buildVoiceIncidentBundle({
22906
+ audit: options.audit,
22907
+ evaluation: options.evaluation,
22908
+ events: options.events,
22909
+ redact: options.redact,
22910
+ sessionId,
22911
+ store: options.store,
22912
+ title: options.title
22913
+ });
22914
+ routes.get(path, async ({ params }) => Response.json(await buildBundle(getSessionId(params)), {
22915
+ headers: options.headers
22916
+ }));
22917
+ if (markdownPath) {
22918
+ routes.get(markdownPath, async ({ params }) => {
22919
+ const bundle = await buildBundle(getSessionId(params));
22920
+ return new Response(bundle.markdown, {
22921
+ headers: {
22922
+ "Content-Type": "text/markdown; charset=utf-8",
22923
+ ...options.headers
22924
+ }
22925
+ });
22926
+ });
22927
+ }
22928
+ return routes;
22929
+ };
22647
22930
  // src/opsStatus.ts
22648
22931
  var DEFAULT_LINKS2 = [
22649
22932
  {
@@ -22816,7 +23099,7 @@ var summarizeVoiceOpsStatus = async (options) => {
22816
23099
  };
22817
23100
  };
22818
23101
  // src/opsStatusRoutes.ts
22819
- import { Elysia as Elysia38 } from "elysia";
23102
+ import { Elysia as Elysia39 } from "elysia";
22820
23103
  var escapeHtml40 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
22821
23104
  var renderVoiceOpsStatusHTML = (report, options = {}) => {
22822
23105
  const title = options.title ?? "AbsoluteJS Voice Ops Status";
@@ -22828,7 +23111,7 @@ var renderVoiceOpsStatusHTML = (report, options = {}) => {
22828
23111
  };
22829
23112
  var createVoiceOpsStatusRoutes = (options) => {
22830
23113
  const path = options.path ?? "/api/voice/ops-status";
22831
- const routes = new Elysia38({
23114
+ const routes = new Elysia39({
22832
23115
  name: options.name ?? "absolutejs-voice-ops-status"
22833
23116
  });
22834
23117
  routes.get(path, async () => summarizeVoiceOpsStatus(options));
@@ -23261,7 +23544,7 @@ var createVoiceTTSProviderRouter = (options) => {
23261
23544
  };
23262
23545
  };
23263
23546
  // src/traceDeliveryRoutes.ts
23264
- import { Elysia as Elysia39 } from "elysia";
23547
+ import { Elysia as Elysia40 } from "elysia";
23265
23548
  var escapeHtml41 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
23266
23549
  var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
23267
23550
  var getNumber10 = (value) => {
@@ -23370,7 +23653,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
23370
23653
  const path = options.path ?? "/api/voice-trace-deliveries";
23371
23654
  const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
23372
23655
  const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
23373
- const routes = new Elysia39({
23656
+ const routes = new Elysia40({
23374
23657
  name: options.name ?? "absolutejs-voice-trace-deliveries"
23375
23658
  }).get(path, createVoiceTraceDeliveryJSONHandler(options));
23376
23659
  if (htmlPath !== false) {
@@ -23994,7 +24277,7 @@ var createVoiceMemoryStore = () => {
23994
24277
  return { get, getOrCreate, list, remove, set };
23995
24278
  };
23996
24279
  // src/opsWebhook.ts
23997
- import { Elysia as Elysia40 } from "elysia";
24280
+ import { Elysia as Elysia41 } from "elysia";
23998
24281
  var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
23999
24282
  var signVoiceOpsWebhookBody = async (input) => {
24000
24283
  const encoder = new TextEncoder;
@@ -24124,7 +24407,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
24124
24407
  };
24125
24408
  var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
24126
24409
  const path = options.path ?? "/api/voice-ops/webhook";
24127
- return new Elysia40().post(path, async ({ body, request, set }) => {
24410
+ return new Elysia41().post(path, async ({ body, request, set }) => {
24128
24411
  const bodyText = typeof body === "string" ? body : JSON.stringify(body);
24129
24412
  if (options.signingSecret) {
24130
24413
  const verification = await verifyVoiceOpsWebhookSignature({
@@ -25009,6 +25292,7 @@ export {
25009
25292
  signVoicePlivoWebhook,
25010
25293
  shapeTelephonyAssistantText,
25011
25294
  selectVoiceTraceEventsForPrune,
25295
+ saveVoiceIncidentBundleArtifact,
25012
25296
  runVoiceToolContractSuite,
25013
25297
  runVoiceToolContract,
25014
25298
  runVoiceSimulationSuite,
@@ -25101,6 +25385,7 @@ export {
25101
25385
  recommendVoiceReadinessProfile,
25102
25386
  recommendVoiceProviderStack,
25103
25387
  pruneVoiceTraceEvents,
25388
+ pruneVoiceIncidentBundleArtifacts,
25104
25389
  parseVoiceTelephonyWebhookEvent,
25105
25390
  matchesVoiceOpsTaskAssignmentRule,
25106
25391
  markVoiceOpsTaskSLABreached,
@@ -25259,6 +25544,7 @@ export {
25259
25544
  createVoiceMemoryTraceSinkDeliveryStore,
25260
25545
  createVoiceMemoryTraceEventStore,
25261
25546
  createVoiceMemoryStore,
25547
+ createVoiceMemoryIncidentBundleStore,
25262
25548
  createVoiceMemoryHandoffDeliveryStore,
25263
25549
  createVoiceMemoryCampaignStore,
25264
25550
  createVoiceMemoryAuditSinkDeliveryStore,
@@ -25272,6 +25558,7 @@ export {
25272
25558
  createVoiceIntegrationSinkWorker,
25273
25559
  createVoiceIntegrationHTTPSink,
25274
25560
  createVoiceIntegrationEvent,
25561
+ createVoiceIncidentBundleRoutes,
25275
25562
  createVoiceHubSpotTaskUpdateSink,
25276
25563
  createVoiceHubSpotTaskSyncSinks,
25277
25564
  createVoiceHubSpotTaskSink,
@@ -25290,6 +25577,7 @@ export {
25290
25577
  createVoiceFileRuntimeStorage,
25291
25578
  createVoiceFileReviewStore,
25292
25579
  createVoiceFileIntegrationEventStore,
25580
+ createVoiceFileIncidentBundleStore,
25293
25581
  createVoiceFileExternalObjectMapStore,
25294
25582
  createVoiceFileEvalBaselineStore,
25295
25583
  createVoiceFileDeliverySink,
@@ -25350,6 +25638,7 @@ export {
25350
25638
  createTelnyxMediaStreamBridge,
25351
25639
  createStoredVoiceOpsTask,
25352
25640
  createStoredVoiceIntegrationEvent,
25641
+ createStoredVoiceIncidentBundleArtifact,
25353
25642
  createStoredVoiceExternalObjectMap,
25354
25643
  createStoredVoiceCallReviewArtifact,
25355
25644
  createRiskyTurnCorrectionHandler,
@@ -25381,6 +25670,7 @@ export {
25381
25670
  buildVoiceOpsConsoleReport,
25382
25671
  buildVoiceOpsActionHistoryReport,
25383
25672
  buildVoiceOperationsRecord,
25673
+ buildVoiceIncidentBundle,
25384
25674
  buildVoiceDiagnosticsMarkdown,
25385
25675
  buildVoiceDemoReadyReport,
25386
25676
  buildVoiceDeliverySinkReport,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.184",
3
+ "version": "0.0.22-beta.186",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",