@absolutejs/voice 0.0.22-beta.486 → 0.0.22-beta.488

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.
@@ -0,0 +1,37 @@
1
+ import type { Transcript, VoiceSessionRecord, VoiceTurnRecord } from "./types";
2
+ import type { VoiceAssistantMemoryNamespaceInput } from "./assistantMemory";
3
+ export type VoiceCallerIdentity = {
4
+ email?: string;
5
+ externalId?: string;
6
+ phone?: string;
7
+ };
8
+ export type VoiceCallerMemorySnapshot = {
9
+ facts: Record<string, string>;
10
+ identity: VoiceCallerIdentity;
11
+ lastSessionAt: number;
12
+ openActions: string[];
13
+ summary: string;
14
+ };
15
+ export declare const VOICE_CALLER_MEMORY_KEY = "caller-memory-snapshot";
16
+ export declare const buildVoiceCallerMemoryNamespace: (identity: VoiceCallerIdentity | undefined, prefix?: string) => string;
17
+ export type CreateVoiceCallerMemoryNamespaceOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord> = {
18
+ identifyCaller: (input: VoiceAssistantMemoryNamespaceInput<TContext, TSession>) => Promise<VoiceCallerIdentity | undefined> | VoiceCallerIdentity | undefined;
19
+ prefix?: string;
20
+ };
21
+ export declare const createVoiceCallerMemoryNamespace: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord>(options: CreateVoiceCallerMemoryNamespaceOptions<TContext, TSession>) => (input: VoiceAssistantMemoryNamespaceInput<TContext, TSession>) => Promise<string>;
22
+ export type VoiceCallerMemoryCompletion = (input: {
23
+ prompt: string;
24
+ systemPrompt?: string;
25
+ }) => Promise<string>;
26
+ export type SummarizeVoiceCallerTranscriptOptions = {
27
+ completion: VoiceCallerMemoryCompletion;
28
+ previousSnapshot?: VoiceCallerMemorySnapshot;
29
+ systemPrompt?: string;
30
+ };
31
+ export type VoiceCallerMemorySummarizerInput = {
32
+ identity: VoiceCallerIdentity;
33
+ options: SummarizeVoiceCallerTranscriptOptions;
34
+ transcripts?: Transcript[];
35
+ turns: VoiceTurnRecord[];
36
+ };
37
+ export declare const summarizeVoiceCallerTranscript: (input: VoiceCallerMemorySummarizerInput) => Promise<VoiceCallerMemorySnapshot>;
package/dist/index.d.ts CHANGED
@@ -81,6 +81,10 @@ export { describeVoiceAssistantMode, resolveVoiceAssistantMode, } from "./assist
81
81
  export type { VoiceAssistantMode, VoiceAssistantModality, VoiceAssistantModeDescriptor, VoiceSemanticVADConfig, } from "./assistantMode";
82
82
  export { createPunctuationSemanticTurnDetector, createRegexSemanticTurnDetector, } from "./semanticTurn";
83
83
  export { VOICE_WEBHOOK_SIGNATURE_HEADER, VOICE_WEBHOOK_TIMESTAMP_HEADER, extractVoiceWebhookSignatureFromHeaders, signVoiceWebhookBody, verifyVoiceWebhookSignature, } from "./webhookVerification";
84
+ export { createVoiceIVRSession, describeVoiceIVRPlan, evaluateVoiceIVRPlan, } from "./ivrPlan";
85
+ export type { VoiceIVRBranch, VoiceIVRDecision, VoiceIVRInput, VoiceIVRMatch, VoiceIVRPlan, VoiceIVRSession, } from "./ivrPlan";
86
+ export { VOICE_CALLER_MEMORY_KEY, buildVoiceCallerMemoryNamespace, createVoiceCallerMemoryNamespace, summarizeVoiceCallerTranscript, } from "./callerMemory";
87
+ export type { CreateVoiceCallerMemoryNamespaceOptions, SummarizeVoiceCallerTranscriptOptions, VoiceCallerIdentity, VoiceCallerMemoryCompletion, VoiceCallerMemorySnapshot, VoiceCallerMemorySummarizerInput, } from "./callerMemory";
84
88
  export { aggregateVoiceTurnLatencySpans, buildOTELSpanId, buildOTELTraceId, buildVoiceOTELPayload, createVoiceOTELHTTPExporter, } from "./otelExporter";
85
89
  export type { VoiceOTELAttribute, VoiceOTELExporter, VoiceOTELExporterOptions, VoiceOTELPayload, VoiceOTELResourceSpans, VoiceOTELSpan, VoiceTurnLatencySpanSet, VoiceTurnLatencySpanStage, } from "./otelExporter";
86
90
  export type { VoiceWebhookVerificationInput, VoiceWebhookVerificationReason, VoiceWebhookVerificationResult, } from "./webhookVerification";
package/dist/index.js CHANGED
@@ -35475,6 +35475,181 @@ var extractVoiceWebhookSignatureFromHeaders = (headers) => {
35475
35475
  timestamp: get(VOICE_WEBHOOK_TIMESTAMP_HEADER)
35476
35476
  };
35477
35477
  };
35478
+ // src/ivrPlan.ts
35479
+ var speechMatchesPattern = (pattern, speech) => {
35480
+ const normalized = speech.toLowerCase().trim();
35481
+ if (pattern instanceof RegExp) {
35482
+ return pattern.test(normalized);
35483
+ }
35484
+ const target = pattern.toLowerCase().trim();
35485
+ if (!target) {
35486
+ return false;
35487
+ }
35488
+ return normalized.includes(target);
35489
+ };
35490
+ var digitsMatchPattern = (pattern, input) => {
35491
+ return input === pattern;
35492
+ };
35493
+ var branchMatches = (branch, input) => {
35494
+ const matcher = branch.match;
35495
+ if (matcher.digit && input.digits) {
35496
+ if (input.digits === matcher.digit) {
35497
+ return true;
35498
+ }
35499
+ }
35500
+ if (matcher.digits && input.digits) {
35501
+ if (digitsMatchPattern(matcher.digits, input.digits)) {
35502
+ return true;
35503
+ }
35504
+ }
35505
+ if (matcher.speech && input.speech) {
35506
+ if (speechMatchesPattern(matcher.speech, input.speech)) {
35507
+ return true;
35508
+ }
35509
+ }
35510
+ return false;
35511
+ };
35512
+ var evaluateVoiceIVRPlan = (plan, input) => {
35513
+ if (!input.digits && !input.speech) {
35514
+ return { reason: "timeout" };
35515
+ }
35516
+ for (const branch of plan.branches) {
35517
+ if (branchMatches(branch, input)) {
35518
+ return { branch, reason: "matched" };
35519
+ }
35520
+ }
35521
+ if (plan.fallbackBranchId) {
35522
+ const fallback = plan.branches.find((branch) => branch.id === plan.fallbackBranchId);
35523
+ if (fallback) {
35524
+ return { branch: fallback, reason: "fallback" };
35525
+ }
35526
+ }
35527
+ return { reason: "no-match" };
35528
+ };
35529
+ var createVoiceIVRSession = (plan) => {
35530
+ const maxAttempts = plan.maxAttempts ?? 3;
35531
+ let attempts = 0;
35532
+ return {
35533
+ attempt: () => attempts,
35534
+ decide: (input) => {
35535
+ attempts += 1;
35536
+ return evaluateVoiceIVRPlan(plan, input);
35537
+ },
35538
+ exhausted: () => attempts >= maxAttempts,
35539
+ reset: () => {
35540
+ attempts = 0;
35541
+ }
35542
+ };
35543
+ };
35544
+ var describeVoiceIVRPlan = (plan) => {
35545
+ const lines = [plan.greeting];
35546
+ for (const branch of plan.branches) {
35547
+ const triggers = [];
35548
+ if (branch.match.digit) {
35549
+ triggers.push(`press ${branch.match.digit}`);
35550
+ }
35551
+ if (branch.match.digits) {
35552
+ triggers.push(`press ${branch.match.digits}`);
35553
+ }
35554
+ if (branch.match.speech) {
35555
+ triggers.push(`say "${branch.match.speech instanceof RegExp ? branch.match.speech.source : branch.match.speech}"`);
35556
+ }
35557
+ lines.push(`- ${branch.label}: ${triggers.join(" or ")}`);
35558
+ }
35559
+ return lines.join(`
35560
+ `);
35561
+ };
35562
+ // src/callerMemory.ts
35563
+ var VOICE_CALLER_MEMORY_KEY = "caller-memory-snapshot";
35564
+ var normalizeIdentifier = (value) => value.trim().replace(/[^a-zA-Z0-9+@._-]/g, "-").toLowerCase();
35565
+ var buildVoiceCallerMemoryNamespace = (identity, prefix = "caller") => {
35566
+ const identifier = identity?.externalId ?? identity?.phone ?? identity?.email ?? "anonymous";
35567
+ return `${prefix}:${normalizeIdentifier(identifier)}`;
35568
+ };
35569
+ var createVoiceCallerMemoryNamespace = (options) => async (input) => {
35570
+ const identity = await Promise.resolve(options.identifyCaller(input));
35571
+ return buildVoiceCallerMemoryNamespace(identity, options.prefix);
35572
+ };
35573
+ var DEFAULT_SYSTEM_PROMPT2 = "You write structured caller memory snapshots for a voice agent. " + "Given the latest call transcript (and an optional previous snapshot), " + "merge them into JSON with shape " + '{"summary":"\u2026","facts":{"key":"value"},"openActions":["\u2026"]}. ' + "Keep summary under 240 chars. Facts must be short value strings (name, plan, last_issue). " + "openActions are concrete follow-ups still pending. JSON only.";
35574
+ var buildTranscriptBlock = (turns) => turns.map((turn, index) => {
35575
+ const userText = turn.text.trim();
35576
+ const assistantText = typeof turn.assistantText === "string" ? turn.assistantText.trim() : "";
35577
+ const lines = [`Turn ${index + 1}:`];
35578
+ if (userText) {
35579
+ lines.push(` user: ${userText}`);
35580
+ }
35581
+ if (assistantText) {
35582
+ lines.push(` agent: ${assistantText}`);
35583
+ }
35584
+ return lines.join(`
35585
+ `);
35586
+ }).join(`
35587
+ `);
35588
+ var extractJson2 = (raw) => {
35589
+ const trimmed = raw.trim();
35590
+ if (!trimmed) {
35591
+ throw new Error("Caller-memory summarizer returned empty response");
35592
+ }
35593
+ const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(trimmed);
35594
+ const candidate = fenced ? fenced[1].trim() : trimmed;
35595
+ try {
35596
+ return JSON.parse(candidate);
35597
+ } catch {
35598
+ const start = candidate.indexOf("{");
35599
+ const end = candidate.lastIndexOf("}");
35600
+ if (start >= 0 && end > start) {
35601
+ return JSON.parse(candidate.slice(start, end + 1));
35602
+ }
35603
+ throw new Error("Caller-memory response was not valid JSON");
35604
+ }
35605
+ };
35606
+ var coerceFacts = (input) => {
35607
+ if (!input || typeof input !== "object") {
35608
+ return {};
35609
+ }
35610
+ const out = {};
35611
+ for (const [key, value] of Object.entries(input)) {
35612
+ if (typeof value === "string") {
35613
+ out[key] = value;
35614
+ } else if (value !== null && value !== undefined) {
35615
+ out[key] = String(value);
35616
+ }
35617
+ }
35618
+ return out;
35619
+ };
35620
+ var coerceActions = (input) => {
35621
+ if (!Array.isArray(input)) {
35622
+ return [];
35623
+ }
35624
+ return input.map((value) => typeof value === "string" ? value.trim() : "").filter((value) => value.length > 0);
35625
+ };
35626
+ var summarizeVoiceCallerTranscript = async (input) => {
35627
+ const transcriptBlock = buildTranscriptBlock(input.turns);
35628
+ const previousBlock = input.options.previousSnapshot ? `Previous snapshot:
35629
+ ${JSON.stringify(input.options.previousSnapshot, null, 2)}
35630
+
35631
+ ` : "";
35632
+ const prompt = `${previousBlock}Latest call transcript:
35633
+ ${transcriptBlock}
35634
+
35635
+ Return JSON only.`;
35636
+ const raw = await input.options.completion({
35637
+ prompt,
35638
+ systemPrompt: input.options.systemPrompt ?? DEFAULT_SYSTEM_PROMPT2
35639
+ });
35640
+ const parsed = extractJson2(raw);
35641
+ if (!parsed || typeof parsed !== "object") {
35642
+ throw new Error("Caller-memory summarizer returned non-object JSON");
35643
+ }
35644
+ const record = parsed;
35645
+ return {
35646
+ facts: coerceFacts(record.facts),
35647
+ identity: input.identity,
35648
+ lastSessionAt: Date.now(),
35649
+ openActions: coerceActions(record.openActions ?? record.open_actions),
35650
+ summary: typeof record.summary === "string" ? record.summary : ""
35651
+ };
35652
+ };
35478
35653
  // src/otelExporter.ts
35479
35654
  var SCOPE_NAME = "@absolutejs/voice";
35480
35655
  var SPAN_KIND_INTERNAL = 1;
@@ -46222,6 +46397,7 @@ export {
46222
46397
  summarizeVoiceHandoffHealth,
46223
46398
  summarizeVoiceHandoffDeliveries,
46224
46399
  summarizeVoiceCampaigns,
46400
+ summarizeVoiceCallerTranscript,
46225
46401
  summarizeVoiceBrowserMedia,
46226
46402
  summarizeVoiceBargeIn,
46227
46403
  summarizeVoiceAuditTrail,
@@ -46461,6 +46637,7 @@ export {
46461
46637
  evaluateVoiceMediaPipelineEvidence,
46462
46638
  evaluateVoiceLiveOpsEvidence,
46463
46639
  evaluateVoiceLiveOpsControlEvidence,
46640
+ evaluateVoiceIVRPlan,
46464
46641
  evaluateVoiceGuardrailPolicy,
46465
46642
  evaluateVoiceDataControlEvidence,
46466
46643
  evaluateVoiceCompetitiveCoverage,
@@ -46470,6 +46647,7 @@ export {
46470
46647
  evaluateVoiceAgentSquadContractEvidence,
46471
46648
  encodeTwilioMulawBase64,
46472
46649
  encodePcmAsWav,
46650
+ describeVoiceIVRPlan,
46473
46651
  describeVoiceAssistantMode,
46474
46652
  deliverVoiceTraceEventsToSinks,
46475
46653
  deliverVoiceObservabilityExport,
@@ -46715,6 +46893,7 @@ export {
46715
46893
  createVoiceIncidentBundleRoutes,
46716
46894
  createVoiceInMemoryRealCallProfileRecoveryJobStore,
46717
46895
  createVoiceInMemoryMonitorRegistry,
46896
+ createVoiceIVRSession,
46718
46897
  createVoiceHubSpotTaskUpdateSink,
46719
46898
  createVoiceHubSpotTaskSyncSinks,
46720
46899
  createVoiceHubSpotTaskSink,
@@ -46770,6 +46949,7 @@ export {
46770
46949
  createVoiceCampaignTelephonyOutcomeHandler,
46771
46950
  createVoiceCampaignRoutes,
46772
46951
  createVoiceCampaign,
46952
+ createVoiceCallerMemoryNamespace,
46773
46953
  createVoiceCallReviewRecorder,
46774
46954
  createVoiceCallReviewFromSession,
46775
46955
  createVoiceCallReviewFromLiveTelephonyReport,
@@ -46922,6 +47102,7 @@ export {
46922
47102
  buildVoiceDataControlReport,
46923
47103
  buildVoiceCompetitiveCoverageReport,
46924
47104
  buildVoiceCampaignObservabilityReport,
47105
+ buildVoiceCallerMemoryNamespace,
46925
47106
  buildVoiceCallDebuggerReport,
46926
47107
  buildVoiceBrowserCallProfileReport,
46927
47108
  buildVoiceAuditTrailReport,
@@ -46984,6 +47165,7 @@ export {
46984
47165
  VOICE_WEBHOOK_TIMESTAMP_HEADER,
46985
47166
  VOICE_WEBHOOK_SIGNATURE_HEADER,
46986
47167
  VOICE_LIVE_OPS_ACTIONS,
47168
+ VOICE_CALLER_MEMORY_KEY,
46987
47169
  TURN_PROFILE_DEFAULTS,
46988
47170
  DEFAULT_VOICE_REDACTION_PATTERNS,
46989
47171
  DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS,
@@ -0,0 +1,40 @@
1
+ export type VoiceIVRMatch = {
2
+ digit?: string;
3
+ digits?: string;
4
+ speech?: string | RegExp;
5
+ };
6
+ export type VoiceIVRBranch = {
7
+ assistantId?: string;
8
+ description?: string;
9
+ id: string;
10
+ label: string;
11
+ match: VoiceIVRMatch;
12
+ metadata?: Record<string, unknown>;
13
+ target?: string;
14
+ };
15
+ export type VoiceIVRPlan = {
16
+ branches: readonly VoiceIVRBranch[];
17
+ fallbackBranchId?: string;
18
+ greeting: string;
19
+ maxAttempts?: number;
20
+ noMatchPrompt?: string;
21
+ timeoutMs?: number;
22
+ timeoutPrompt?: string;
23
+ };
24
+ export type VoiceIVRInput = {
25
+ digits?: string;
26
+ speech?: string;
27
+ };
28
+ export type VoiceIVRDecision = {
29
+ branch?: VoiceIVRBranch;
30
+ reason: "matched" | "no-match" | "fallback" | "timeout";
31
+ };
32
+ export declare const evaluateVoiceIVRPlan: (plan: VoiceIVRPlan, input: VoiceIVRInput) => VoiceIVRDecision;
33
+ export type VoiceIVRSession = {
34
+ attempt: () => number;
35
+ decide: (input: VoiceIVRInput) => VoiceIVRDecision;
36
+ exhausted: () => boolean;
37
+ reset: () => void;
38
+ };
39
+ export declare const createVoiceIVRSession: (plan: VoiceIVRPlan) => VoiceIVRSession;
40
+ export declare const describeVoiceIVRPlan: (plan: VoiceIVRPlan) => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.486",
3
+ "version": "0.0.22-beta.488",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",