@absolutejs/voice 0.0.22-beta.210 → 0.0.22-beta.212

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.
Files changed (2) hide show
  1. package/README.md +238 -0
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -479,6 +479,244 @@ The UI should keep the scheduling flow simple: microphone, transcript, selected
479
479
 
480
480
  This recipe covers the hosted-platform expectations that matter for appointment scheduling: scheduling tools, deterministic tool proof, post-call confirmation work, outcome validation, simulation proof, production readiness, and one call-log replacement for debugging.
481
481
 
482
+ ## Use-Case Recipe: Campaign Outreach
483
+
484
+ Use this path when you need Retell/Bland-style outbound outreach without handing recipients, consent proof, attempt policy, carrier outcomes, or debugging records to a hosted campaign dashboard. The package gives you campaign primitives; your app decides who can upload recipients, when workers run, which carrier dials, and how campaign results sync back to your product.
485
+
486
+ The production shape is:
487
+
488
+ 1. Store campaigns in app-owned storage.
489
+ 2. Import recipients with consent checks, phone validation, dedupe, variables, and rejected-row evidence.
490
+ 3. Configure campaign policy for max attempts, concurrency, attempt windows, quiet hours, rate limits, and retry backoff.
491
+ 4. Use a carrier dialer or your own dialer function, then apply Twilio/Telnyx/Plivo webhook outcomes back to attempts.
492
+ 5. Expose campaign routes, observability, readiness proof, production readiness, and operations-record links for every attempted call.
493
+
494
+ ```ts
495
+ import { Elysia } from 'elysia';
496
+ import {
497
+ createVoiceCampaignRoutes,
498
+ createVoiceFileRuntimeStorage,
499
+ createVoiceOperationsRecordRoutes,
500
+ createVoiceProductionReadinessRoutes,
501
+ createVoiceReadinessProfile,
502
+ createVoiceSQLiteCampaignStore,
503
+ runVoiceCampaignReadinessProof
504
+ } from '@absolutejs/voice';
505
+
506
+ const runtime = createVoiceFileRuntimeStorage({
507
+ directory: '.voice-runtime/campaign-outreach'
508
+ });
509
+
510
+ const campaigns = createVoiceSQLiteCampaignStore({
511
+ path: '.voice-runtime/campaigns.sqlite'
512
+ });
513
+
514
+ const app = new Elysia()
515
+ .use(
516
+ createVoiceCampaignRoutes({
517
+ htmlPath: '/voice/campaigns',
518
+ operationsRecordHref: '/voice-operations/:sessionId',
519
+ path: '/api/voice/campaigns',
520
+ store: campaigns,
521
+ title: 'Renewal Outreach'
522
+ })
523
+ )
524
+ .use(
525
+ createVoiceOperationsRecordRoutes({
526
+ htmlPath: '/voice-operations/:sessionId',
527
+ path: '/api/voice-operations/:sessionId',
528
+ store: runtime.traces
529
+ })
530
+ )
531
+ .use(
532
+ createVoiceProductionReadinessRoutes({
533
+ ...createVoiceReadinessProfile('phone-agent', {
534
+ campaignReadiness: () =>
535
+ runVoiceCampaignReadinessProof({
536
+ store: campaigns
537
+ }),
538
+ explain: true
539
+ }),
540
+ links: {
541
+ campaigns: '/voice/campaigns',
542
+ operationsRecords: '/voice-operations/:sessionId'
543
+ },
544
+ store: runtime.traces
545
+ })
546
+ );
547
+
548
+ await fetch('/api/voice/campaigns', {
549
+ body: JSON.stringify({
550
+ maxAttempts: 3,
551
+ maxConcurrentAttempts: 10,
552
+ name: 'Renewal outreach',
553
+ schedule: {
554
+ attemptWindow: { startHour: 9, endHour: 17 },
555
+ quietHours: { startHour: 12, endHour: 13 },
556
+ rateLimit: { maxAttempts: 60, windowMs: 60_000 },
557
+ retryPolicy: { backoffMs: [5 * 60_000, 30 * 60_000] }
558
+ }
559
+ }),
560
+ headers: { 'content-type': 'application/json' },
561
+ method: 'POST'
562
+ });
563
+
564
+ await fetch('/api/voice/campaigns/campaign-1/recipients/import', {
565
+ body: JSON.stringify({
566
+ csv: `id,name,phone,consent,segment
567
+ recipient-1,Ada,+15550001001,yes,trial
568
+ recipient-2,Grace,+15550001002,true,enterprise
569
+ recipient-3,Linus,not-a-phone,yes,partner
570
+ recipient-4,Barbara,+15550001004,no,trial`,
571
+ metadataColumns: ['segment'],
572
+ requireConsent: true,
573
+ variableColumns: ['segment']
574
+ }),
575
+ headers: { 'content-type': 'application/json' },
576
+ method: 'POST'
577
+ });
578
+
579
+ await fetch('/api/voice/campaigns/campaign-1/enqueue', {
580
+ method: 'POST'
581
+ });
582
+ ```
583
+
584
+ Use `/api/voice/campaigns/campaign-1/tick` for manual workers or `createVoiceCampaignWorkerLoop(...)` when the app should continuously drain eligible recipients. The runtime enforces the campaign policy on each tick, so parallel workers do not double-start recipients and attempts respect quiet hours, rate limits, retry backoff, and max attempts.
585
+
586
+ For production carrier dialing, pass a `dialer` to `createVoiceCampaignRoutes(...)`: `createVoiceTwilioCampaignDialer(...)`, `createVoiceTelnyxCampaignDialer(...)`, `createVoicePlivoCampaignDialer(...)`, or a custom dialer that starts the call and returns an external call id. Run `runVoiceCampaignDialerProof(...)` before live traffic to dry-run carrier request metadata and webhook outcome application.
587
+
588
+ The UI should show `/voice/campaigns`, `/voice/campaigns/observability`, `/api/voice/campaigns/readiness-proof`, `/production-readiness`, and operations-record links for recent attempts. If a recipient failed, the operator should open the campaign attempt, follow `/voice-operations/:sessionId`, and see the same trace/review/task/audit context used by support and phone-agent flows.
589
+
590
+ This recipe covers the hosted-platform expectations that matter for campaign outreach: recipient import evidence, consent/dedupe checks, scheduling policy, worker-safe attempts, carrier dry-run proof, webhook outcome mapping, queue observability, readiness gating, and call-log replacement links.
591
+
592
+ ## Use-Case Recipe: Meeting Recorder
593
+
594
+ Use this path when the product needs a browser recorder for meetings, interviews, demos, or internal calls: capture microphone audio, persist transcripts and traces, generate a post-call review, expose a replayable operations record, and keep retention/export controls inside the app. This is not a hosted meeting bot; it is a set of recorder primitives your AbsoluteJS UI can own.
595
+
596
+ The production shape is:
597
+
598
+ 1. Mount a browser voice route with persistent session, trace, review, task, and audit-capable storage.
599
+ 2. Use framework stream/controller helpers for the microphone, transcript, reconnect state, and recording status.
600
+ 3. Persist a review artifact on completion with transcript, summary, latency, outcome, and recommended follow-up.
601
+ 4. Mount trace timelines, operations records, production readiness, and data-control routes.
602
+ 5. Gate release with the `meeting-recorder` readiness profile so reconnect, barge-in/interruption, provider routing, latency, and session-health proof stay visible.
603
+
604
+ ```ts
605
+ import { Elysia } from 'elysia';
606
+ import {
607
+ createVoiceDataControlRoutes,
608
+ createVoiceFileRuntimeStorage,
609
+ createVoiceOperationsRecordRoutes,
610
+ createVoiceProductionReadinessRoutes,
611
+ createVoiceReadinessProfile,
612
+ createVoiceTraceTimelineRoutes,
613
+ voice,
614
+ voiceComplianceRedactionDefaults
615
+ } from '@absolutejs/voice';
616
+ import { deepgram } from '@absolutejs/voice-deepgram';
617
+
618
+ const runtime = createVoiceFileRuntimeStorage({
619
+ directory: '.voice-runtime/meeting-recorder'
620
+ });
621
+
622
+ const app = new Elysia()
623
+ .use(
624
+ voice({
625
+ path: '/voice/meeting-recorder',
626
+ preset: 'reliability',
627
+ session: runtime.session,
628
+ stt: deepgram({
629
+ apiKey: process.env.DEEPGRAM_API_KEY!,
630
+ model: 'flux-general-en'
631
+ }),
632
+ trace: runtime.traces,
633
+ async onTurn({ turn }) {
634
+ return {
635
+ assistantText: '',
636
+ metadata: {
637
+ recorder: true,
638
+ transcript: turn.text
639
+ }
640
+ };
641
+ },
642
+ onComplete: async () => {},
643
+ ops: {
644
+ events: runtime.events,
645
+ reviews: runtime.reviews,
646
+ tasks: runtime.tasks,
647
+ buildReview: ({ session }) => ({
648
+ errors: [],
649
+ latencyBreakdown: [],
650
+ notes: ['Generated by the self-hosted meeting recorder path.'],
651
+ postCall: {
652
+ label: 'Meeting summary',
653
+ recommendedAction: 'Review the transcript and share action items.',
654
+ summary: 'Review transcript, decisions, and follow-up owners.'
655
+ },
656
+ summary: {
657
+ outcome: 'completed',
658
+ pass: true,
659
+ turnCount: session.turns.length
660
+ },
661
+ title: `Meeting recorder review for ${session.id}`,
662
+ timeline: [],
663
+ transcript: {
664
+ actual: session.turns
665
+ .map((turn) => turn.text)
666
+ .filter(Boolean)
667
+ .join('\n')
668
+ }
669
+ })
670
+ }
671
+ })
672
+ )
673
+ .use(
674
+ createVoiceTraceTimelineRoutes({
675
+ htmlPath: '/traces',
676
+ path: '/api/voice-traces',
677
+ store: runtime.traces
678
+ })
679
+ )
680
+ .use(
681
+ createVoiceOperationsRecordRoutes({
682
+ htmlPath: '/voice-operations/:sessionId',
683
+ integrationEvents: runtime.events,
684
+ path: '/api/voice-operations/:sessionId',
685
+ reviews: runtime.reviews,
686
+ store: runtime.traces,
687
+ tasks: runtime.tasks
688
+ })
689
+ )
690
+ .use(
691
+ createVoiceDataControlRoutes({
692
+ ...runtime,
693
+ audit: runtime.audit,
694
+ auditDeliveries: runtime.auditDeliveries,
695
+ redact: voiceComplianceRedactionDefaults,
696
+ traceDeliveries: runtime.traceDeliveries
697
+ })
698
+ )
699
+ .use(
700
+ createVoiceProductionReadinessRoutes({
701
+ ...createVoiceReadinessProfile('meeting-recorder', {
702
+ explain: true
703
+ }),
704
+ links: {
705
+ dataControl: '/data-control',
706
+ operationsRecords: '/voice-operations/:sessionId',
707
+ traces: '/traces'
708
+ },
709
+ store: runtime.traces
710
+ })
711
+ );
712
+ ```
713
+
714
+ The UI should show a clear recording button, elapsed time, live transcript, reconnect state, recording status, a stop/finalize action, and links to `/voice-operations/:sessionId`, `/traces`, `/production-readiness`, and `/data-control`. Use `useVoiceStream(...)`, `useVoiceController(...)`, `createVoiceStream(...)`, `VoiceStreamService`, or the HTML/HTMX client helpers depending on the framework; the route and trace/review stores stay the same.
715
+
716
+ For customer-facing exports, use the same redaction/export primitives as support workflows: render trace Markdown or audit Markdown with `voiceComplianceRedactionDefaults`, then deliver it through file, webhook, or S3 delivery runtimes. For sensitive recordings, start with a retention dry run through `/data-control/retention/plan` before applying deletion.
717
+
718
+ This recipe covers the hosted-platform expectations that matter for meeting recorders: browser mic capture, live transcript UI, reconnect visibility, post-call review, transcript/debug record, readiness proof, customer-owned storage, retention controls, and redacted export paths.
719
+
482
720
  ## How This Differs From Hosted Voice Platforms
483
721
 
484
722
  Hosted voice-agent platforms are strongest when you want a managed dashboard, phone-number provisioning, hosted orchestration, and campaign tooling out of the box.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.210",
3
+ "version": "0.0.22-beta.212",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",