@absolutejs/voice 0.0.22-beta.358 → 0.0.22-beta.359

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/dist/index.js CHANGED
@@ -5467,18 +5467,26 @@ var recommendVoiceProfileSwitch = (options) => {
5467
5467
  var applyVoiceProfileSwitchGuard = async (options) => {
5468
5468
  const mode = options.mode ?? "recommend";
5469
5469
  const minConfidence = options.minConfidence ?? 0.75;
5470
+ const maxAutoSwitchesPerSession = Math.max(0, Math.floor(options.maxAutoSwitchesPerSession ?? 1));
5471
+ const autoSwitchCount = Math.max(0, Math.floor(options.autoSwitchCount ?? 0));
5470
5472
  const recommendation = recommendVoiceProfileSwitch(options);
5471
5473
  const confidence = estimateSwitchConfidence(recommendation);
5472
5474
  const previousProfileId = recommendation.currentProfile?.profileId;
5473
5475
  const recommendedProfileId = recommendation.recommendedProfile?.profileId;
5474
- const canSwitch = recommendation.status === "switch" && recommendation.ok && Boolean(recommendedProfileId) && confidence >= minConfidence;
5475
- const action = recommendation.status === "stay" ? "stay" : canSwitch ? mode === "auto" ? "switch" : "recommend" : "blocked";
5476
+ const isRecommendedAllowed = !recommendedProfileId || !options.allowedProfileIds || options.allowedProfileIds.length === 0 || options.allowedProfileIds.includes(recommendedProfileId);
5477
+ const isRecommendedBlocked = recommendedProfileId ? Boolean(options.blockedProfileIds?.includes(recommendedProfileId)) : false;
5478
+ const blockedByPolicy = !isRecommendedAllowed ? "allowed-profiles" : isRecommendedBlocked ? "blocked-profiles" : mode === "auto" && autoSwitchCount >= maxAutoSwitchesPerSession ? "max-switches" : undefined;
5479
+ const canSwitch = mode !== "off" && recommendation.status === "switch" && recommendation.ok && Boolean(recommendedProfileId) && confidence >= minConfidence && !blockedByPolicy;
5480
+ const action = mode === "off" ? "disabled" : recommendation.status === "stay" ? "stay" : canSwitch ? mode === "auto" ? "switch" : "recommend" : "blocked";
5476
5481
  const selectedProfileId = action === "switch" ? recommendedProfileId : previousProfileId ?? recommendedProfileId;
5477
- const reason = action === "switch" ? `Auto-switched from ${previousProfileId ?? "unknown"} to ${recommendedProfileId}.` : action === "recommend" ? `Recommended ${recommendedProfileId} but left selection unchanged because mode is recommend.` : action === "blocked" ? `Blocked profile switch because confidence ${confidence} is below ${minConfidence} or evidence is incomplete.` : "Kept current profile because measured evidence does not require a switch.";
5482
+ const reason = action === "disabled" ? "Profile switch guard is disabled by policy." : action === "switch" ? `Auto-switched from ${previousProfileId ?? "unknown"} to ${recommendedProfileId}.` : action === "recommend" ? `Recommended ${recommendedProfileId} but left selection unchanged because mode is recommend.` : action === "blocked" ? blockedByPolicy === "allowed-profiles" ? `Blocked profile switch because ${recommendedProfileId} is not in the allowed profile list.` : blockedByPolicy === "blocked-profiles" ? `Blocked profile switch because ${recommendedProfileId} is in the blocked profile list.` : blockedByPolicy === "max-switches" ? `Blocked profile switch because the session already used ${autoSwitchCount} of ${maxAutoSwitchesPerSession} allowed automatic switch(es).` : `Blocked profile switch because confidence ${confidence} is below ${minConfidence} or evidence is incomplete.` : "Kept current profile because measured evidence does not require a switch.";
5478
5483
  const decision = {
5479
5484
  action,
5480
5485
  autoApplied: action === "switch",
5486
+ autoSwitchCount,
5487
+ blockedByPolicy,
5481
5488
  confidence,
5489
+ maxAutoSwitchesPerSession,
5482
5490
  minConfidence,
5483
5491
  mode,
5484
5492
  previousProfileId,
@@ -5496,10 +5504,13 @@ var applyVoiceProfileSwitchGuard = async (options) => {
5496
5504
  name: "AbsoluteJS Voice Profile Switch Guard"
5497
5505
  },
5498
5506
  metadata: options.metadata,
5499
- outcome: action === "blocked" ? "skipped" : "success",
5507
+ outcome: action === "blocked" || action === "disabled" ? "skipped" : "success",
5500
5508
  payload: {
5501
5509
  autoApplied: decision.autoApplied,
5510
+ autoSwitchCount,
5511
+ blockedByPolicy,
5502
5512
  confidence,
5513
+ maxAutoSwitchesPerSession,
5503
5514
  minConfidence,
5504
5515
  mode,
5505
5516
  previousProfileId,
@@ -5732,12 +5743,19 @@ var resolveProfileSwitchGuard = async (config, runtime, input) => {
5732
5743
  const currentProfileId = await resolveMaybeFunction(guard.currentProfileId, resolverInput);
5733
5744
  const metadata = await resolveMaybeFunction(guard.metadata, resolverInput);
5734
5745
  const minConfidence = await resolveMaybeFunction(guard.minConfidence, resolverInput);
5746
+ const maxAutoSwitchesPerSession = await resolveMaybeFunction(guard.maxAutoSwitchesPerSession, resolverInput);
5747
+ const allowedProfileIds = await resolveMaybeFunction(guard.allowedProfileIds, resolverInput);
5748
+ const blockedProfileIds = await resolveMaybeFunction(guard.blockedProfileIds, resolverInput);
5735
5749
  const mode = await resolveMaybeFunction(guard.mode, resolverInput);
5736
5750
  const decision = await applyVoiceProfileSwitchGuard({
5737
5751
  actor: guard.actor,
5752
+ allowedProfileIds,
5738
5753
  audit: guard.audit,
5754
+ autoSwitchCount: runtime.profileSwitchGuardAutoSwitchCounts.get(input.sessionId) ?? 0,
5755
+ blockedProfileIds,
5739
5756
  defaultProfileId: guard.defaultProfileId,
5740
5757
  defaults,
5758
+ maxAutoSwitchesPerSession,
5741
5759
  metadata,
5742
5760
  minConfidence,
5743
5761
  mode,
@@ -5747,6 +5765,9 @@ var resolveProfileSwitchGuard = async (config, runtime, input) => {
5747
5765
  },
5748
5766
  sessionId: input.sessionId
5749
5767
  });
5768
+ if (decision.autoApplied) {
5769
+ runtime.profileSwitchGuardAutoSwitchCounts.set(input.sessionId, decision.autoSwitchCount + 1);
5770
+ }
5750
5771
  await guard.onDecision?.({
5751
5772
  context: input.context,
5752
5773
  decision,
@@ -5764,7 +5785,10 @@ var resolveProfileSwitchGuard = async (config, runtime, input) => {
5764
5785
  payload: {
5765
5786
  action: decision.action,
5766
5787
  autoApplied: decision.autoApplied,
5788
+ autoSwitchCount: decision.autoSwitchCount,
5789
+ blockedByPolicy: decision.blockedByPolicy,
5767
5790
  confidence: decision.confidence,
5791
+ maxAutoSwitchesPerSession: decision.maxAutoSwitchesPerSession,
5768
5792
  minConfidence: decision.minConfidence,
5769
5793
  mode: decision.mode,
5770
5794
  previousProfileId: decision.previousProfileId,
@@ -5787,6 +5811,7 @@ var voice = (config) => {
5787
5811
  const runtime = {
5788
5812
  activeSessions: new Map,
5789
5813
  logger: resolveLogger(config.logger),
5814
+ profileSwitchGuardAutoSwitchCounts: new Map,
5790
5815
  profileSwitchGuardedSessions: new Set,
5791
5816
  socketSessions: new WeakMap
5792
5817
  };
@@ -36,15 +36,18 @@ export type VoiceProfileSwitchRecommendationOptions = {
36
36
  minImprovementMs?: number;
37
37
  observed?: VoiceProfileSwitchObservedSignals;
38
38
  };
39
- export type VoiceProfileSwitchGuardMode = 'auto' | 'recommend';
40
- export type VoiceProfileSwitchGuardAction = 'blocked' | 'recommend' | 'stay' | 'switch';
39
+ export type VoiceProfileSwitchGuardMode = 'auto' | 'off' | 'recommend';
40
+ export type VoiceProfileSwitchGuardAction = 'blocked' | 'disabled' | 'recommend' | 'stay' | 'switch';
41
41
  export type VoiceProfileSwitchGuardDecision = {
42
42
  action: VoiceProfileSwitchGuardAction;
43
43
  auditEvent?: StoredVoiceAuditEvent;
44
44
  autoApplied: boolean;
45
+ autoSwitchCount: number;
46
+ blockedByPolicy?: 'allowed-profiles' | 'blocked-profiles' | 'max-switches';
45
47
  confidence: number;
46
48
  minConfidence: number;
47
49
  mode: VoiceProfileSwitchGuardMode;
50
+ maxAutoSwitchesPerSession: number;
48
51
  previousProfileId?: string;
49
52
  reason: string;
50
53
  recommendation: VoiceProfileSwitchRecommendation;
@@ -53,7 +56,11 @@ export type VoiceProfileSwitchGuardDecision = {
53
56
  };
54
57
  export type VoiceProfileSwitchGuardOptions = VoiceProfileSwitchRecommendationOptions & {
55
58
  actor?: VoiceAuditActor;
59
+ allowedProfileIds?: string[];
56
60
  audit?: VoiceAuditEventStore;
61
+ autoSwitchCount?: number;
62
+ blockedProfileIds?: string[];
63
+ maxAutoSwitchesPerSession?: number;
57
64
  metadata?: Record<string, unknown>;
58
65
  minConfidence?: number;
59
66
  mode?: VoiceProfileSwitchGuardMode;
package/dist/types.d.ts CHANGED
@@ -624,12 +624,15 @@ export type VoiceProfileSwitchGuardResolverInput<TContext = unknown> = {
624
624
  };
625
625
  export type VoicePluginProfileSwitchGuardConfig<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
626
626
  actor?: VoiceAuditActor;
627
+ allowedProfileIds?: string[] | ((input: VoiceProfileSwitchGuardResolverInput<TContext>) => Promise<string[] | undefined> | string[] | undefined);
627
628
  audit?: VoiceAuditEventStore;
629
+ blockedProfileIds?: string[] | ((input: VoiceProfileSwitchGuardResolverInput<TContext>) => Promise<string[] | undefined> | string[] | undefined);
628
630
  currentProfileId?: string | ((input: VoiceProfileSwitchGuardResolverInput<TContext>) => Promise<string | undefined> | string | undefined);
629
631
  defaultProfileId?: string;
630
632
  defaults: VoiceRealCallProfileDefaultsReport | VoiceRealCallProfileHistoryReport | ((input: VoiceProfileSwitchGuardResolverInput<TContext>) => Promise<VoiceRealCallProfileDefaultsReport | VoiceRealCallProfileHistoryReport> | VoiceRealCallProfileDefaultsReport | VoiceRealCallProfileHistoryReport);
631
633
  metadata?: Record<string, unknown> | ((input: VoiceProfileSwitchGuardResolverInput<TContext>) => Promise<Record<string, unknown> | undefined> | Record<string, unknown> | undefined);
632
634
  minConfidence?: number | ((input: VoiceProfileSwitchGuardResolverInput<TContext>) => Promise<number | undefined> | number | undefined);
635
+ maxAutoSwitchesPerSession?: number | ((input: VoiceProfileSwitchGuardResolverInput<TContext>) => Promise<number | undefined> | number | undefined);
633
636
  mode?: VoiceProfileSwitchGuardMode | ((input: VoiceProfileSwitchGuardResolverInput<TContext>) => Promise<VoiceProfileSwitchGuardMode | undefined> | VoiceProfileSwitchGuardMode | undefined);
634
637
  observed?: VoiceProfileSwitchObservedSignals | ((input: VoiceProfileSwitchGuardResolverInput<TContext>) => Promise<VoiceProfileSwitchObservedSignals | undefined> | VoiceProfileSwitchObservedSignals | undefined);
635
638
  onDecision?: (input: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.358",
3
+ "version": "0.0.22-beta.359",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",