@absolutejs/voice 0.0.22-beta.211 → 0.0.22-beta.213
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/README.md +249 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -589,6 +589,255 @@ The UI should show `/voice/campaigns`, `/voice/campaigns/observability`, `/api/v
|
|
|
589
589
|
|
|
590
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
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
|
+
|
|
720
|
+
## Use-Case Recipe: Compliance-Sensitive Calls
|
|
721
|
+
|
|
722
|
+
Use this path when the voice app handles sensitive customer support, healthcare-adjacent intake, financial workflows, internal investigations, or regulated customer data. AbsoluteJS Voice can provide self-hosted controls and evidence: customer-owned storage, provider-key ownership, redaction defaults, audit trails, guarded deletion, zero-retention policy helpers, redacted exports, and deploy gates. It does not certify the app for HIPAA, SOC 2, GDPR, or any other legal regime by itself.
|
|
723
|
+
|
|
724
|
+
The production shape is:
|
|
725
|
+
|
|
726
|
+
1. Use customer-owned runtime storage, preferably Postgres for production records and S3/webhook delivery for exported evidence.
|
|
727
|
+
2. Keep provider keys in the app owner environment, not in a hosted voice dashboard.
|
|
728
|
+
3. Pass `audit` into agents/tools/squads so provider calls, tool executions, handoffs, retention runs, and operator actions are recorded.
|
|
729
|
+
4. Mount data-control routes for redacted audit export, retention dry-runs, guarded deletion, zero-retention planning, and provider-key recommendations.
|
|
730
|
+
5. Make audit evidence, recent retention-policy evidence, and audit/trace delivery health part of production readiness.
|
|
731
|
+
|
|
732
|
+
```ts
|
|
733
|
+
import { Elysia } from 'elysia';
|
|
734
|
+
import {
|
|
735
|
+
applyVoiceDataRetentionPolicy,
|
|
736
|
+
buildVoiceDataRetentionPlan,
|
|
737
|
+
createVoiceAuditLogger,
|
|
738
|
+
createVoiceDataControlRoutes,
|
|
739
|
+
createVoiceOperationsRecordRoutes,
|
|
740
|
+
createVoicePostgresRuntimeStorage,
|
|
741
|
+
createVoiceProductionReadinessRoutes,
|
|
742
|
+
createVoiceZeroRetentionPolicy,
|
|
743
|
+
exportVoiceAuditTrail,
|
|
744
|
+
renderVoiceAuditMarkdown,
|
|
745
|
+
voiceComplianceRedactionDefaults
|
|
746
|
+
} from '@absolutejs/voice';
|
|
747
|
+
|
|
748
|
+
const runtime = createVoicePostgresRuntimeStorage({
|
|
749
|
+
connectionString: process.env.DATABASE_URL!,
|
|
750
|
+
schemaName: 'voice_ops',
|
|
751
|
+
tablePrefix: 'sensitive'
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
const audit = createVoiceAuditLogger(runtime.audit);
|
|
755
|
+
|
|
756
|
+
const app = new Elysia()
|
|
757
|
+
.use(
|
|
758
|
+
createVoiceDataControlRoutes({
|
|
759
|
+
...runtime,
|
|
760
|
+
audit: runtime.audit,
|
|
761
|
+
auditDeliveries: runtime.auditDeliveries,
|
|
762
|
+
path: '/data-control',
|
|
763
|
+
redact: voiceComplianceRedactionDefaults,
|
|
764
|
+
title: 'Sensitive Voice Data Control',
|
|
765
|
+
traceDeliveries: runtime.traceDeliveries
|
|
766
|
+
})
|
|
767
|
+
)
|
|
768
|
+
.use(
|
|
769
|
+
createVoiceOperationsRecordRoutes({
|
|
770
|
+
audit: runtime.audit,
|
|
771
|
+
htmlPath: '/voice-operations/:sessionId',
|
|
772
|
+
integrationEvents: runtime.events,
|
|
773
|
+
path: '/api/voice-operations/:sessionId',
|
|
774
|
+
reviews: runtime.reviews,
|
|
775
|
+
store: runtime.traces,
|
|
776
|
+
tasks: runtime.tasks
|
|
777
|
+
})
|
|
778
|
+
)
|
|
779
|
+
.use(
|
|
780
|
+
createVoiceProductionReadinessRoutes({
|
|
781
|
+
audit: {
|
|
782
|
+
require: [
|
|
783
|
+
{ type: 'provider.call' },
|
|
784
|
+
{ type: 'operator.action' },
|
|
785
|
+
{ type: 'retention.policy', maxAgeMs: 7 * 24 * 60 * 60 * 1000 }
|
|
786
|
+
],
|
|
787
|
+
store: runtime.audit
|
|
788
|
+
},
|
|
789
|
+
auditDeliveries: runtime.auditDeliveries,
|
|
790
|
+
links: {
|
|
791
|
+
audit: '/audit',
|
|
792
|
+
auditDeliveries: '/audit/deliveries',
|
|
793
|
+
dataControl: '/data-control',
|
|
794
|
+
operationsRecords: '/voice-operations/:sessionId',
|
|
795
|
+
traceDeliveries: '/traces/deliveries'
|
|
796
|
+
},
|
|
797
|
+
store: runtime.traces,
|
|
798
|
+
traceDeliveries: runtime.traceDeliveries
|
|
799
|
+
})
|
|
800
|
+
);
|
|
801
|
+
|
|
802
|
+
await audit.operatorAction({
|
|
803
|
+
action: 'retention.policy.reviewed',
|
|
804
|
+
actor: { id: 'ops-admin', type: 'operator' },
|
|
805
|
+
outcome: 'ok',
|
|
806
|
+
resource: { id: 'zero-retention-policy', type: 'voice.retention' }
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
const zeroRetentionPolicy = createVoiceZeroRetentionPolicy({
|
|
810
|
+
...runtime,
|
|
811
|
+
audit: runtime.audit,
|
|
812
|
+
auditDeliveries: runtime.auditDeliveries,
|
|
813
|
+
traceDeliveries: runtime.traceDeliveries
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
const retentionPlan = await buildVoiceDataRetentionPlan(zeroRetentionPolicy);
|
|
817
|
+
|
|
818
|
+
if (retentionPlan.deletedCount > 0) {
|
|
819
|
+
await applyVoiceDataRetentionPolicy({
|
|
820
|
+
...zeroRetentionPolicy,
|
|
821
|
+
dryRun: false
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
const auditExport = await exportVoiceAuditTrail({
|
|
826
|
+
redact: voiceComplianceRedactionDefaults,
|
|
827
|
+
store: runtime.audit
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
const redactedAuditMarkdown = renderVoiceAuditMarkdown(auditExport.events, {
|
|
831
|
+
title: 'Sensitive Voice Audit Export'
|
|
832
|
+
});
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
For the actual agent or squad, pass the same `audit` logger into `createVoiceAgent(...)`, `createVoiceAgentSquad(...)`, or `createVoiceAssistant(...)` with explicit `auditProvider` and `auditModel` labels. That makes provider usage and tool execution visible in `/data-control/audit.md`, `/audit`, readiness checks, and operations records.
|
|
836
|
+
|
|
837
|
+
The UI should expose `/data-control`, `/data-control.json`, `/data-control/audit.md`, `/data-control/retention/plan`, `/production-readiness`, and `/voice-operations/:sessionId`. Destructive retention application should remain a server-side operator action that first reviews the dry-run plan and then posts `confirm: "apply-retention-policy"`.
|
|
838
|
+
|
|
839
|
+
This recipe covers the hosted-platform expectations that matter for compliance-sensitive voice apps: customer-owned records, provider-key ownership, redacted exports, audit evidence, guarded retention, zero-retention planning, deploy gates, and a clear boundary that the package supplies controls and proof artifacts, not legal certification.
|
|
840
|
+
|
|
592
841
|
## How This Differs From Hosted Voice Platforms
|
|
593
842
|
|
|
594
843
|
Hosted voice-agent platforms are strongest when you want a managed dashboard, phone-number provisioning, hosted orchestration, and campaign tooling out of the box.
|