@memberjunction/ng-conversations 5.43.0 → 5.44.0
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/lib/components/active-tasks/active-tasks-panel.component.d.ts +0 -1
- package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts.map +1 -1
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js +56 -52
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js.map +1 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.js +37 -41
- package/dist/lib/components/artifact/artifact-share-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-form-modal.component.js +10 -14
- package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-share-modal.component.js +41 -45
- package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-view.component.js +22 -36
- package/dist/lib/components/collection/collection-view.component.js.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.d.ts +4 -0
- package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.js +134 -166
- package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +73 -8
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +487 -123
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.js +6 -9
- package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
- package/dist/lib/components/library/library-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/library/library-full-view.component.js +20 -24
- package/dist/lib/components/library/library-full-view.component.js.map +1 -1
- package/dist/lib/components/members/members-modal.component.d.ts.map +1 -1
- package/dist/lib/components/members/members-modal.component.js +10 -11
- package/dist/lib/components/members/members-modal.component.js.map +1 -1
- package/dist/lib/components/mention/mention-dropdown.component.js +49 -28
- package/dist/lib/components/mention/mention-dropdown.component.js.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.d.ts.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.js +24 -10
- package/dist/lib/components/mention/mention-editor.component.js.map +1 -1
- package/dist/lib/components/message/message-input-box.component.d.ts +11 -16
- package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input-box.component.js +52 -46
- package/dist/lib/components/message/message-input-box.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +83 -18
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +238 -151
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +10 -1
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +67 -15
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.js +6 -9
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.d.ts +3 -0
- package/dist/lib/components/overlay/chat-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.js +9 -4
- package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +45 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +10 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +1 -1
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts +46 -0
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/channels/client-context-channel.js +174 -0
- package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.d.ts +123 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.js +397 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-state.d.ts +103 -0
- package/dist/lib/components/realtime/media/media-channel-state.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-state.js +143 -0
- package/dist/lib/components/realtime/media/media-channel-state.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-tools.d.ts +24 -0
- package/dist/lib/components/realtime/media/media-channel-tools.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-tools.js +107 -0
- package/dist/lib/components/realtime/media/media-channel-tools.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts +89 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/media-channel.js +253 -0
- package/dist/lib/components/realtime/media/media-channel.js.map +1 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.d.ts +141 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.js +574 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +59 -14
- package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-activity-rail.component.js +277 -74
- package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +28 -27
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.js +144 -143
- package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +12 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.js +105 -43
- package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +2 -2
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.d.ts +41 -7
- package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.js +216 -102
- package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +0 -2
- package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-delegation-card.component.js +67 -71
- package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +364 -44
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +839 -153
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-state.d.ts +5 -5
- package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-state.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tab-style.d.ts +70 -0
- package/dist/lib/components/realtime/realtime-surface-tab-style.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tab-style.js +115 -0
- package/dist/lib/components/realtime/realtime-surface-tab-style.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +55 -57
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js +165 -143
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +80 -71
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js +83 -113
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.d.ts +270 -0
- package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-ui-config.js +212 -0
- package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -0
- package/dist/lib/components/search/search-panel.component.d.ts +2 -0
- package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
- package/dist/lib/components/search/search-panel.component.js +92 -101
- package/dist/lib/components/search/search-panel.component.js.map +1 -1
- package/dist/lib/components/share/share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/share/share-modal.component.js +10 -11
- package/dist/lib/components/share/share-modal.component.js.map +1 -1
- package/dist/lib/components/shared/user-picker.component.d.ts.map +1 -1
- package/dist/lib/components/shared/user-picker.component.js +12 -15
- package/dist/lib/components/shared/user-picker.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +5 -0
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +18 -7
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/conversations.module.d.ts +29 -26
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +37 -6
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/models/conversation-state.model.d.ts +6 -3
- package/dist/lib/models/conversation-state.model.d.ts.map +1 -1
- package/dist/lib/models/conversation-state.model.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +2 -2
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +6 -2
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/mention-autocomplete.service.d.ts +17 -1
- package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
- package/dist/lib/services/mention-autocomplete.service.js +58 -2
- package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.d.ts +143 -0
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -0
- package/dist/lib/services/realtime-audio-recorder.js +379 -0
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -0
- package/dist/lib/services/realtime-pcm-wav.d.ts +75 -0
- package/dist/lib/services/realtime-pcm-wav.d.ts.map +1 -0
- package/dist/lib/services/realtime-pcm-wav.js +205 -0
- package/dist/lib/services/realtime-pcm-wav.js.map +1 -0
- package/dist/lib/services/realtime-session-review.service.d.ts +28 -1
- package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session-review.service.js +12 -3
- package/dist/lib/services/realtime-session-review.service.js.map +1 -1
- package/dist/lib/services/realtime-session.service.d.ts +210 -20
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +452 -21
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/realtime-sessions-adapter.js +1 -1
- package/dist/lib/services/realtime-sessions-adapter.js.map +1 -1
- package/dist/lib/services/ui-command-handler.service.d.ts +7 -2
- package/dist/lib/services/ui-command-handler.service.d.ts.map +1 -1
- package/dist/lib/services/ui-command-handler.service.js +6 -2
- package/dist/lib/services/ui-command-handler.service.js.map +1 -1
- package/dist/lib/utils/plan-mode-preference.d.ts +62 -0
- package/dist/lib/utils/plan-mode-preference.d.ts.map +1 -0
- package/dist/lib/utils/plan-mode-preference.js +130 -0
- package/dist/lib/utils/plan-mode-preference.js.map +1 -0
- package/dist/public-api.d.ts +6 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +8 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +28 -26
- package/dist/__tests__/attachment-badge.test.d.ts +0 -2
- package/dist/__tests__/attachment-badge.test.d.ts.map +0 -1
- package/dist/__tests__/attachment-badge.test.js +0 -66
- package/dist/__tests__/attachment-badge.test.js.map +0 -1
- package/dist/__tests__/channel-optional-surface.test.d.ts +0 -2
- package/dist/__tests__/channel-optional-surface.test.d.ts.map +0 -1
- package/dist/__tests__/channel-optional-surface.test.js +0 -53
- package/dist/__tests__/channel-optional-surface.test.js.map +0 -1
- package/dist/__tests__/chat-events.test.d.ts +0 -14
- package/dist/__tests__/chat-events.test.d.ts.map +0 -1
- package/dist/__tests__/chat-events.test.js +0 -109
- package/dist/__tests__/chat-events.test.js.map +0 -1
- package/dist/__tests__/collections-full-view.test.d.ts +0 -2
- package/dist/__tests__/collections-full-view.test.d.ts.map +0 -1
- package/dist/__tests__/collections-full-view.test.js +0 -225
- package/dist/__tests__/collections-full-view.test.js.map +0 -1
- package/dist/__tests__/conversation-cache.test.d.ts +0 -2
- package/dist/__tests__/conversation-cache.test.d.ts.map +0 -1
- package/dist/__tests__/conversation-cache.test.js +0 -233
- package/dist/__tests__/conversation-cache.test.js.map +0 -1
- package/dist/__tests__/conversation-naming.test.d.ts +0 -2
- package/dist/__tests__/conversation-naming.test.d.ts.map +0 -1
- package/dist/__tests__/conversation-naming.test.js +0 -110
- package/dist/__tests__/conversation-naming.test.js.map +0 -1
- package/dist/__tests__/delegation-result-parser.test.d.ts +0 -2
- package/dist/__tests__/delegation-result-parser.test.d.ts.map +0 -1
- package/dist/__tests__/delegation-result-parser.test.js +0 -107
- package/dist/__tests__/delegation-result-parser.test.js.map +0 -1
- package/dist/__tests__/distinct-artifacts.test.d.ts +0 -2
- package/dist/__tests__/distinct-artifacts.test.d.ts.map +0 -1
- package/dist/__tests__/distinct-artifacts.test.js +0 -56
- package/dist/__tests__/distinct-artifacts.test.js.map +0 -1
- package/dist/__tests__/event-wiring.test.d.ts +0 -15
- package/dist/__tests__/event-wiring.test.d.ts.map +0 -1
- package/dist/__tests__/event-wiring.test.js +0 -100
- package/dist/__tests__/event-wiring.test.js.map +0 -1
- package/dist/__tests__/index.test.d.ts +0 -2
- package/dist/__tests__/index.test.d.ts.map +0 -1
- package/dist/__tests__/index.test.js +0 -7
- package/dist/__tests__/index.test.js.map +0 -1
- package/dist/__tests__/narration-template.test.d.ts +0 -2
- package/dist/__tests__/narration-template.test.d.ts.map +0 -1
- package/dist/__tests__/narration-template.test.js +0 -76
- package/dist/__tests__/narration-template.test.js.map +0 -1
- package/dist/__tests__/notification-model.test.d.ts +0 -2
- package/dist/__tests__/notification-model.test.d.ts.map +0 -1
- package/dist/__tests__/notification-model.test.js +0 -68
- package/dist/__tests__/notification-model.test.js.map +0 -1
- package/dist/__tests__/realtime-agent-picker-models.test.d.ts +0 -2
- package/dist/__tests__/realtime-agent-picker-models.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-agent-picker-models.test.js +0 -49
- package/dist/__tests__/realtime-agent-picker-models.test.js.map +0 -1
- package/dist/__tests__/realtime-audio-visuals.test.d.ts +0 -2
- package/dist/__tests__/realtime-audio-visuals.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-audio-visuals.test.js +0 -123
- package/dist/__tests__/realtime-audio-visuals.test.js.map +0 -1
- package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts +0 -2
- package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-delegation-card-cancel.test.js +0 -48
- package/dist/__tests__/realtime-delegation-card-cancel.test.js.map +0 -1
- package/dist/__tests__/realtime-disclosure.test.d.ts +0 -2
- package/dist/__tests__/realtime-disclosure.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-disclosure.test.js +0 -164
- package/dist/__tests__/realtime-disclosure.test.js.map +0 -1
- package/dist/__tests__/realtime-pairing.test.d.ts +0 -2
- package/dist/__tests__/realtime-pairing.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-pairing.test.js +0 -207
- package/dist/__tests__/realtime-pairing.test.js.map +0 -1
- package/dist/__tests__/realtime-review-lifecycle.test.d.ts +0 -2
- package/dist/__tests__/realtime-review-lifecycle.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-review-lifecycle.test.js +0 -154
- package/dist/__tests__/realtime-review-lifecycle.test.js.map +0 -1
- package/dist/__tests__/realtime-session-cancel-usage.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-cancel-usage.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-cancel-usage.test.js +0 -230
- package/dist/__tests__/realtime-session-cancel-usage.test.js.map +0 -1
- package/dist/__tests__/realtime-session-channels.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-channels.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-channels.test.js +0 -252
- package/dist/__tests__/realtime-session-channels.test.js.map +0 -1
- package/dist/__tests__/realtime-session-client-tools.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-client-tools.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-client-tools.test.js +0 -103
- package/dist/__tests__/realtime-session-client-tools.test.js.map +0 -1
- package/dist/__tests__/realtime-session-minimized.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-minimized.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-minimized.test.js +0 -32
- package/dist/__tests__/realtime-session-minimized.test.js.map +0 -1
- package/dist/__tests__/realtime-session-mint.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-mint.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-mint.test.js +0 -69
- package/dist/__tests__/realtime-session-mint.test.js.map +0 -1
- package/dist/__tests__/realtime-session-policy.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-policy.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-policy.test.js +0 -303
- package/dist/__tests__/realtime-session-policy.test.js.map +0 -1
- package/dist/__tests__/realtime-session-review.service.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-review.service.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-review.service.test.js +0 -743
- package/dist/__tests__/realtime-session-review.service.test.js.map +0 -1
- package/dist/__tests__/realtime-session-state.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-state.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-state.test.js +0 -83
- package/dist/__tests__/realtime-session-state.test.js.map +0 -1
- package/dist/__tests__/realtime-session-timeline-card.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-timeline-card.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-timeline-card.test.js +0 -106
- package/dist/__tests__/realtime-session-timeline-card.test.js.map +0 -1
- package/dist/__tests__/realtime-session-timeline.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-timeline.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-timeline.test.js +0 -142
- package/dist/__tests__/realtime-session-timeline.test.js.map +0 -1
- package/dist/__tests__/realtime-sessions-adapter.test.d.ts +0 -19
- package/dist/__tests__/realtime-sessions-adapter.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-sessions-adapter.test.js +0 -188
- package/dist/__tests__/realtime-sessions-adapter.test.js.map +0 -1
- package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts +0 -2
- package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-surface-panel-prefs.test.js +0 -100
- package/dist/__tests__/realtime-surface-panel-prefs.test.js.map +0 -1
- package/dist/__tests__/realtime-surface-tabs-model.test.d.ts +0 -2
- package/dist/__tests__/realtime-surface-tabs-model.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-surface-tabs-model.test.js +0 -193
- package/dist/__tests__/realtime-surface-tabs-model.test.js.map +0 -1
- package/dist/__tests__/remote-browser-audio-player.test.d.ts +0 -2
- package/dist/__tests__/remote-browser-audio-player.test.d.ts.map +0 -1
- package/dist/__tests__/remote-browser-audio-player.test.js +0 -137
- package/dist/__tests__/remote-browser-audio-player.test.js.map +0 -1
- package/dist/__tests__/remote-browser-channel.test.d.ts +0 -2
- package/dist/__tests__/remote-browser-channel.test.d.ts.map +0 -1
- package/dist/__tests__/remote-browser-channel.test.js +0 -585
- package/dist/__tests__/remote-browser-channel.test.js.map +0 -1
- package/dist/__tests__/search-service.test.d.ts +0 -2
- package/dist/__tests__/search-service.test.d.ts.map +0 -1
- package/dist/__tests__/search-service.test.js +0 -114
- package/dist/__tests__/search-service.test.js.map +0 -1
- package/dist/__tests__/slot-defaults.test.d.ts +0 -24
- package/dist/__tests__/slot-defaults.test.d.ts.map +0 -1
- package/dist/__tests__/slot-defaults.test.js +0 -63
- package/dist/__tests__/slot-defaults.test.js.map +0 -1
- package/dist/__tests__/toast-service.test.d.ts +0 -2
- package/dist/__tests__/toast-service.test.d.ts.map +0 -1
- package/dist/__tests__/toast-service.test.js +0 -143
- package/dist/__tests__/toast-service.test.js.map +0 -1
- package/dist/__tests__/user-authorization.test.d.ts +0 -2
- package/dist/__tests__/user-authorization.test.d.ts.map +0 -1
- package/dist/__tests__/user-authorization.test.js +0 -97
- package/dist/__tests__/user-authorization.test.js.map +0 -1
- package/dist/__tests__/voice-session-narration.test.d.ts +0 -2
- package/dist/__tests__/voice-session-narration.test.d.ts.map +0 -1
- package/dist/__tests__/voice-session-narration.test.js +0 -609
- package/dist/__tests__/voice-session-narration.test.js.map +0 -1
- package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts +0 -2
- package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts.map +0 -1
- package/dist/__tests__/whiteboard-artifact-viewer.test.js +0 -101
- package/dist/__tests__/whiteboard-artifact-viewer.test.js.map +0 -1
- package/dist/__tests__/whiteboard-channel.test.d.ts +0 -2
- package/dist/__tests__/whiteboard-channel.test.d.ts.map +0 -1
- package/dist/__tests__/whiteboard-channel.test.js +0 -260
- package/dist/__tests__/whiteboard-channel.test.js.map +0 -1
- package/dist/__tests__/whiteboard-restore-state.test.d.ts +0 -2
- package/dist/__tests__/whiteboard-restore-state.test.d.ts.map +0 -1
- package/dist/__tests__/whiteboard-restore-state.test.js +0 -108
- package/dist/__tests__/whiteboard-restore-state.test.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-agent-picker.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-agent-picker.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n HostListener,\n Input,\n OnInit,\n Output,\n ViewChild,\n AfterViewInit,\n inject,\n} from '@angular/core';\nimport type { MJAIAgentEntityExtended } from '@memberjunction/ai-core-plus';\nimport { MJButtonDirective } from '@memberjunction/ng-ui-components';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { REALTIME_ADVANCED_SESSION_CONTROLS, UserHoldsAuthorization } from '../../services/user-authorization';\nimport {\n BuildRealtimeModelOptions,\n ConstrainTargetsToPairings,\n DefaultPairedTargetId,\n LoadCoAgentPairings,\n RealtimeModelOption,\n RealtimePairedAgentRow,\n} from '../../services/realtime-pairing';\nimport { GraphQLLiveKitClient, GraphQLDataProvider, RealtimeModelVoices, RealtimeVoiceOption } from '@memberjunction/graphql-dataprovider';\n\n/**\n * The user's confirmed choice from the realtime picker: the agent to call, an optional\n * EXPLICIT realtime model (`null` = \"Auto (recommended)\", i.e. let the server pick —\n * always `null` for users without the `Realtime: Advanced Session Controls`\n * authorization, who never see the model selector), and an optional EXPLICIT co-agent\n * (`null` = the server's co-agent resolution chain).\n */\nexport interface RealtimeAgentPick {\n /** The agent the voice call should front. */\n Agent: MJAIAgentEntityExtended;\n /** Explicit realtime model id, or `null` for the server's automatic selection. */\n PreferredModelId: string | null;\n /** Explicit provider-native voice id (e.g. `echo`), or `null` for the configured/default voice. */\n PreferredVoice: string | null;\n /** Explicit co-agent id (`MJ: AI Agents.ID`, Realtime type), or `null` for the server's resolution chain. */\n CoAgentId: string | null;\n}\n\n/**\n * Compact anchored popover that lets the user choose WHICH agent a realtime\n * voice call should front — shown by {@link MessageInputComponent} when the\n * phone button is clicked on a conversation with **no prior agent\n * participation** (new / empty conversation), and on demand via the caret\n * button next to the phone (any conversation), where it doubles as the way\n * to pick a specific **co-agent** (the Realtime-type agent that voices the\n * call) and — for authorized users — a specific **voice model**. The plain\n * phone click on an existing conversation keeps its friction-free \"call the\n * resolved agent immediately\" behavior.\n *\n * Mostly dumb: the host supplies the agent list (the same cached set the\n * @mention autocomplete / routing logic uses), the Realtime-type co-agent\n * candidates (filtered from that same set), and the defaults to preselect;\n * the picker emits the user's choice. The data it loads itself:\n * - the compact \"Voice model\" option list (active Realtime models via a\n * narrow RunView) — loaded and rendered ONLY when the current user holds\n * the `Realtime: Advanced Session Controls` authorization (pure UX\n * disclosure; the server enforces the authorization on the mint), and\n * - the chosen co-agent's pairing rows (`MJ: AI Agent Co Agents`, Active 'CoAgent'-type rows): a\n * co-agent with pairing rows may only front its paired targets, so the\n * agent list constrains to those rows (Sequence order) with the IsDefault\n * row preselected; a co-agent with zero rows is universal and the list is\n * untouched.\n *\n * It does NOT persist anything (the host persists the co-agent preference\n * via `UserInfoEngine`; `mj-conversation-agent-picker` pins\n * `MJConversationEntity.DefaultAgentID` — different jobs, which is why this\n * is a separate component).\n *\n * Anchors itself bottom-right above the composer — the host's\n * `.message-input-wrapper` is `position: relative`.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-agent-picker',\n imports: [MJButtonDirective],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"mj-voice-picker\" (click)=\"$event.stopPropagation()\">\n <div class=\"mj-voice-picker__header\">\n <i class=\"fa-solid fa-phone\"></i>\n <span>Start a voice call with…</span>\n </div>\n @if (ShowCoAgentSelect) {\n <div class=\"mj-voice-picker__select-row\">\n <label class=\"mj-voice-picker__select-label\" for=\"mjVoiceCoAgentSelect\">\n <i class=\"fa-solid fa-headset\"></i>\n <span>Co-agent</span>\n </label>\n <select\n #coAgentSelect\n id=\"mjVoiceCoAgentSelect\"\n class=\"mj-voice-picker__select\"\n [value]=\"SelectedCoAgentId ?? ''\"\n (change)=\"OnCoAgentChange(coAgentSelect.value)\">\n <option value=\"\">Auto (recommended)</option>\n @for (coAgent of CoAgents; track coAgent.ID) {\n <option [value]=\"coAgent.ID\">{{ coAgent.Name }}</option>\n }\n </select>\n </div>\n }\n <div class=\"mj-voice-picker__search\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <input\n #searchInput\n type=\"text\"\n placeholder=\"Search agents\"\n [value]=\"SearchText\"\n (input)=\"OnSearchInput(searchInput.value)\"\n (keydown.enter)=\"StartCall()\"\n (keydown.arrowdown)=\"MoveSelection(1); $event.preventDefault()\"\n (keydown.arrowup)=\"MoveSelection(-1); $event.preventDefault()\" />\n </div>\n <div class=\"mj-voice-picker__list\">\n @if (FilteredAgents.length === 0) {\n <div class=\"mj-voice-picker__empty\">{{ IsConstrainedByPairings ? 'No paired agents available' : 'No matching agents' }}</div>\n } @else {\n @for (agent of FilteredAgents; track agent.ID) {\n <button\n type=\"button\"\n class=\"mj-voice-picker__item\"\n [class.mj-voice-picker__item--selected]=\"IsSelected(agent)\"\n [title]=\"agent.Description || agent.Name\"\n (click)=\"Select(agent)\"\n (dblclick)=\"Pick(agent)\">\n <i [class]=\"IconClassFor(agent)\"></i>\n <span class=\"mj-voice-picker__item-name\">{{ agent.Name }}</span>\n @if (IsDefaultChoice(agent)) {\n <span class=\"mj-voice-picker__default-badge\">default</span>\n }\n </button>\n }\n }\n </div>\n @if (CanOverrideSessionConfig && Models.length > 0) {\n <div class=\"mj-voice-picker__select-row mj-voice-picker__select-row--model\">\n <label class=\"mj-voice-picker__select-label\" for=\"mjVoiceModelSelect\">\n <i class=\"fa-solid fa-microchip\"></i>\n <span>Voice model</span>\n </label>\n <select\n #modelSelect\n id=\"mjVoiceModelSelect\"\n class=\"mj-voice-picker__select\"\n [value]=\"SelectedModelId ?? ''\"\n (change)=\"OnModelChange(modelSelect.value)\">\n <option value=\"\">Auto (recommended)</option>\n @for (model of Models; track model.ID) {\n <option [value]=\"model.ID\">{{ model.Name }}</option>\n }\n </select>\n </div>\n @if (SelectedModelVoices.length) {\n <div class=\"mj-voice-picker__select-row mj-voice-picker__select-row--model\">\n <label class=\"mj-voice-picker__select-label\" for=\"mjVoiceVoiceSelect\">\n <i class=\"fa-solid fa-waveform-lines\"></i>\n <span>Voice</span>\n </label>\n <select\n #voiceSelect\n id=\"mjVoiceVoiceSelect\"\n class=\"mj-voice-picker__select\"\n [value]=\"SelectedVoiceId ?? ''\"\n (change)=\"OnVoiceChange(voiceSelect.value)\">\n <option value=\"\">Default</option>\n @for (v of SelectedModelVoices; track v.ID) {\n <option [value]=\"v.ID\">{{ v.Name }}</option>\n }\n </select>\n </div>\n }\n }\n <div class=\"mj-voice-picker__footer\">\n <button mjButton variant=\"primary\" size=\"sm\" [disabled]=\"!SelectedAgent\" (click)=\"StartCall()\">\n <i class=\"fa-solid fa-phone\"></i> Start\n </button>\n <button mjButton variant=\"outline\" size=\"sm\" (click)=\"Cancel()\">Cancel</button>\n </div>\n </div>\n `,\n styles: [`\n :host {\n position: absolute;\n bottom: calc(100% + 8px);\n right: 8px;\n z-index: 60;\n }\n .mj-voice-picker {\n width: 300px;\n display: flex; flex-direction: column;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);\n overflow: hidden;\n }\n .mj-voice-picker__header {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 12px 8px;\n font-size: 13px; font-weight: 600;\n color: var(--mj-text-primary);\n }\n .mj-voice-picker__header i { color: var(--mj-brand-primary); }\n .mj-voice-picker__search {\n display: flex; align-items: center; gap: 8px;\n margin: 0 12px 8px;\n padding: 0 10px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n }\n .mj-voice-picker__search i { font-size: 12px; color: var(--mj-text-muted); }\n .mj-voice-picker__search input {\n flex: 1; min-width: 0;\n padding: 7px 0;\n background: transparent; border: none; outline: none;\n font-size: 13px; color: var(--mj-text-primary);\n }\n .mj-voice-picker__search input::placeholder { color: var(--mj-text-disabled); }\n .mj-voice-picker__search:focus-within { border-color: var(--mj-border-focus); }\n .mj-voice-picker__list {\n max-height: 220px; overflow-y: auto;\n border-top: 1px solid var(--mj-border-subtle);\n border-bottom: 1px solid var(--mj-border-subtle);\n padding: 4px 0;\n }\n .mj-voice-picker__item {\n display: flex; align-items: center; gap: 8px; width: 100%;\n padding: 7px 12px;\n background: transparent; border: none; cursor: pointer;\n color: var(--mj-text-primary); font-size: 13px; text-align: left;\n }\n .mj-voice-picker__item i { width: 16px; text-align: center; color: var(--mj-text-secondary); }\n .mj-voice-picker__item:hover { background: var(--mj-bg-surface-hover); }\n .mj-voice-picker__item--selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n .mj-voice-picker__item--selected i { color: var(--mj-brand-primary); }\n .mj-voice-picker__item-name {\n flex: 1; min-width: 0;\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n }\n .mj-voice-picker__default-badge {\n flex-shrink: 0;\n padding: 1px 6px;\n border-radius: 999px;\n font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n }\n .mj-voice-picker__empty {\n padding: 12px; font-size: 12px; color: var(--mj-text-muted); text-align: center;\n }\n .mj-voice-picker__select-row {\n display: flex; align-items: center; gap: 8px;\n padding: 0 12px 8px;\n }\n .mj-voice-picker__select-row--model {\n padding: 8px 12px 0;\n }\n .mj-voice-picker__select-label {\n display: flex; align-items: center; gap: 6px;\n flex-shrink: 0;\n font-size: 12px; color: var(--mj-text-secondary);\n }\n .mj-voice-picker__select-label i { font-size: 11px; color: var(--mj-text-muted); }\n .mj-voice-picker__select {\n flex: 1; min-width: 0;\n padding: 5px 8px;\n font-size: 12px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n outline: none;\n }\n .mj-voice-picker__select:focus { border-color: var(--mj-border-focus); }\n .mj-voice-picker__footer {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 12px;\n }\n `]\n})\nexport class RealtimeAgentPickerComponent extends BaseAngularComponent implements OnInit, AfterViewInit {\n /** Agents the user can call — same cached set the @mention / routing logic uses. */\n @Input() Agents: MJAIAgentEntityExtended[] = [];\n\n /** The agent the default resolution would pick — preselected and listed first. */\n @Input() DefaultAgentId: string | null = null;\n\n /**\n * The ACTIVE Realtime-type co-agent candidates the user can run (host-filtered from\n * the same cached, run-permission-filtered agent set as {@link Agents}). The co-agent\n * selector renders only when MORE THAN ONE candidate exists — with zero or one\n * there's nothing meaningful to choose and the server's resolution chain applies.\n */\n @Input() CoAgents: MJAIAgentEntityExtended[] = [];\n\n /**\n * The user's persisted co-agent preference (host-loaded via `UserInfoEngine`) —\n * preselected in the co-agent selector when it's still a valid candidate.\n */\n @Input() DefaultCoAgentId: string | null = null;\n\n /** Emitted with the chosen agent + optional explicit voice model / co-agent when the user confirms. */\n @Output() AgentPicked = new EventEmitter<RealtimeAgentPick>();\n\n /** Emitted when the user dismisses without starting a call. */\n @Output() Cancelled = new EventEmitter<void>();\n\n @ViewChild('searchInput') private searchInput?: ElementRef<HTMLInputElement>;\n\n public SearchText = '';\n public SelectedAgentId: string | null = null;\n\n /** Active Realtime models the model selector offers (loaded only for authorized users). */\n public Models: RealtimeModelOption[] = [];\n\n /** The explicitly chosen voice model id, or `null` for \"Auto (recommended)\" (the default). */\n public SelectedModelId: string | null = null;\n\n /** Active Realtime models + their voices (for the voice selector); loaded only for authorized users. */\n public VoiceModels: RealtimeModelVoices[] = [];\n\n /** The explicitly chosen voice id, or `null` for the configured/default voice. */\n public SelectedVoiceId: string | null = null;\n\n /** Voices for the currently-selected model (empty when no model picked or it declares none). */\n public get SelectedModelVoices(): RealtimeVoiceOption[] {\n return this.VoiceModels.find((m) => UUIDsEqual(m.ModelID, this.SelectedModelId))?.Voices ?? [];\n }\n\n /** The explicitly chosen co-agent id, or `null` for \"Auto (recommended)\" (the server's chain). */\n public SelectedCoAgentId: string | null = null;\n\n /**\n * Whether the current user holds the `Realtime: Advanced Session Controls`\n * authorization. Gates the voice-model selector (and any future config-override\n * controls) — pure disclosure; the server enforces the authorization on the mint.\n */\n public CanOverrideSessionConfig = false;\n\n /** The selected co-agent's pairing rows; empty = universal co-agent (no constraint). */\n public Pairings: RealtimePairedAgentRow[] = [];\n\n // Template helper — expose the shared UUID comparator to the view.\n public readonly UUIDsEqual = UUIDsEqual;\n\n private readonly cdr = inject(ChangeDetectorRef);\n private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n /** Monotonic guard so a stale pairing load can't clobber a newer co-agent choice. */\n private pairingLoadToken = 0;\n\n /** Co-agent selector visibility: only when there is a real choice to make. */\n public get ShowCoAgentSelect(): boolean {\n return this.CoAgents.length > 1;\n }\n\n /** True while the agent list is constrained to the selected co-agent's paired targets. */\n public get IsConstrainedByPairings(): boolean {\n return this.Pairings.length > 0;\n }\n\n public ngOnInit(): void {\n const initial = this.DefaultAgentId && this.findAgent(this.DefaultAgentId)\n ? this.DefaultAgentId\n : this.FilteredAgents[0]?.ID ?? null;\n this.SelectedAgentId = initial;\n this.CanOverrideSessionConfig = UserHoldsAuthorization(\n this.ProviderToUse?.CurrentUser,\n REALTIME_ADVANCED_SESSION_CONTROLS,\n this.ProviderToUse\n );\n if (this.CanOverrideSessionConfig) {\n void this.loadVoiceModels();\n }\n // Preselect the persisted co-agent preference when it's still a valid candidate.\n if (this.DefaultCoAgentId && this.CoAgents.some(a => UUIDsEqual(a.ID, this.DefaultCoAgentId))) {\n this.SelectedCoAgentId = this.DefaultCoAgentId;\n void this.reloadPairings();\n }\n }\n\n /**\n * Loads the \"Voice model\" options: active models whose type is `Realtime`, filtered from\n * {@link AIEngineBase}'s already-cached `Models` (provider-scoped engine instance, lazy\n * `Config` — no RunView round-trip). Called ONLY for users who hold the\n * advanced-session-controls authorization. Tolerant — a failure simply leaves\n * the selector hidden (the server's automatic selection still applies).\n */\n private async loadVoiceModels(): Promise<void> {\n try {\n const engine = AIEngineBase.GetProviderInstance<AIEngineBase>(this.ProviderToUse, AIEngineBase) as AIEngineBase;\n await engine.Config(false, undefined, this.ProviderToUse);\n this.Models = BuildRealtimeModelOptions(engine.Models ?? []);\n } catch (error) {\n console.error('[RealtimeAgentPicker] Failed to load realtime models:', error);\n this.Models = [];\n }\n // Voices come from the driver via a server query (the cached models carry no voice list).\n try {\n const client = new GraphQLLiveKitClient(this.ProviderToUse as unknown as GraphQLDataProvider);\n this.VoiceModels = await client.GetRealtimeModelVoices();\n } catch (error) {\n console.error('[RealtimeAgentPicker] Failed to load realtime voices:', error);\n this.VoiceModels = [];\n }\n this.cdr.markForCheck();\n }\n\n /** Records the voice-model choice (`''` = Auto → `null`); clears the voice so it can't outlive a switch. */\n public OnModelChange(value: string): void {\n this.SelectedModelId = value && value.length > 0 ? value : null;\n this.SelectedVoiceId = null;\n this.cdr.markForCheck();\n }\n\n /** Records the voice choice (`''` = default → `null`). */\n public OnVoiceChange(value: string): void {\n this.SelectedVoiceId = value && value.length > 0 ? value : null;\n this.cdr.markForCheck();\n }\n\n /** Records the co-agent choice (`''` = Auto → `null`) and refreshes the pairing constraint. */\n public OnCoAgentChange(value: string): void {\n this.SelectedCoAgentId = value && value.length > 0 ? value : null;\n void this.reloadPairings();\n }\n\n /**\n * Loads the selected co-agent's pairing rows and re-applies the target constraint:\n * with rows present, the agent list narrows to the paired targets (Sequence order)\n * and the IsDefault row's target is preselected; with zero rows (or Auto co-agent)\n * the list returns to the unconstrained default. Guarded against stale loads when\n * the user changes co-agents quickly.\n */\n private async reloadPairings(): Promise<void> {\n const token = ++this.pairingLoadToken;\n const coAgentId = this.SelectedCoAgentId;\n const pairings = coAgentId ? await LoadCoAgentPairings(this.ProviderToUse, coAgentId) : [];\n if (token !== this.pairingLoadToken) {\n return; // a newer co-agent choice superseded this load\n }\n this.Pairings = pairings;\n this.ensureSelectionVisible();\n this.cdr.markForCheck();\n }\n\n /**\n * Keeps the target selection coherent after the visible list changes: prefers the\n * pairing default (when constrained), then the host default, then keeps the current\n * selection when still visible, then the first visible row.\n */\n private ensureSelectionVisible(): void {\n const visible = this.FilteredAgents;\n if (this.IsConstrainedByPairings) {\n const pairedDefault = DefaultPairedTargetId(this.Pairings);\n if (pairedDefault && visible.some(a => UUIDsEqual(a.ID, pairedDefault))) {\n this.SelectedAgentId = pairedDefault;\n return;\n }\n }\n if (this.SelectedAgentId && visible.some(a => UUIDsEqual(a.ID, this.SelectedAgentId))) {\n return; // current selection still valid\n }\n if (this.DefaultAgentId && visible.some(a => UUIDsEqual(a.ID, this.DefaultAgentId))) {\n this.SelectedAgentId = this.DefaultAgentId;\n return;\n }\n this.SelectedAgentId = visible[0]?.ID ?? null;\n }\n\n public ngAfterViewInit(): void {\n // Microtask so focus lands after the popover renders without\n // triggering ExpressionChangedAfterItHasBeenChecked.\n Promise.resolve().then(() => this.searchInput?.nativeElement.focus());\n }\n\n /**\n * The visible target list: pairing-constrained first (a co-agent WITH pairing rows may\n * only front its paired targets, kept in pairing Sequence order), then search-filtered.\n * Unconstrained lists keep the default-first + alphabetical ordering.\n */\n public get FilteredAgents(): MJAIAgentEntityExtended[] {\n const base = ConstrainTargetsToPairings(this.Agents, this.Pairings);\n const needle = this.SearchText.trim().toLowerCase();\n const filtered = base.filter(a => !needle || (a.Name ?? '').toLowerCase().includes(needle));\n if (this.IsConstrainedByPairings) {\n return filtered; // pairing Sequence order is the canonical order\n }\n return filtered.sort((a, b) => {\n const aDefault = this.isDefault(a) ? 0 : 1;\n const bDefault = this.isDefault(b) ? 0 : 1;\n if (aDefault !== bDefault) return aDefault - bDefault;\n return (a.Name ?? '').localeCompare(b.Name ?? '');\n });\n }\n\n public get SelectedAgent(): MJAIAgentEntityExtended | null {\n return this.SelectedAgentId ? this.findAgent(this.SelectedAgentId) : null;\n }\n\n public IsSelected(agent: MJAIAgentEntityExtended): boolean {\n return !!this.SelectedAgentId && UUIDsEqual(agent.ID, this.SelectedAgentId);\n }\n\n /**\n * Whether `agent` carries the \"default\" badge: under a pairing constraint that's the\n * co-agent's IsDefault target; otherwise the host-resolved default agent.\n */\n public IsDefaultChoice(agent: MJAIAgentEntityExtended): boolean {\n if (this.IsConstrainedByPairings) {\n const pairedDefault = DefaultPairedTargetId(this.Pairings);\n return !!pairedDefault && UUIDsEqual(agent.ID, pairedDefault);\n }\n return this.isDefault(agent);\n }\n\n public IconClassFor(agent: MJAIAgentEntityExtended): string {\n return agent.IconClass?.trim() || 'fa-solid fa-robot';\n }\n\n public OnSearchInput(value: string): void {\n this.SearchText = value;\n // Keep the selection on a visible row.\n const visible = this.FilteredAgents;\n if (!visible.some(a => this.IsSelected(a))) {\n this.SelectedAgentId = visible[0]?.ID ?? null;\n }\n this.cdr.markForCheck();\n }\n\n /** Arrow-key navigation through the filtered list. */\n public MoveSelection(delta: number): void {\n const visible = this.FilteredAgents;\n if (visible.length === 0) return;\n const currentIndex = visible.findIndex(a => this.IsSelected(a));\n const nextIndex = currentIndex < 0\n ? 0\n : Math.min(visible.length - 1, Math.max(0, currentIndex + delta));\n this.SelectedAgentId = visible[nextIndex].ID;\n this.cdr.markForCheck();\n }\n\n public Select(agent: MJAIAgentEntityExtended): void {\n this.SelectedAgentId = agent.ID;\n this.cdr.markForCheck();\n }\n\n /** Confirm a specific agent immediately (double-click shortcut). */\n public Pick(agent: MJAIAgentEntityExtended): void {\n this.AgentPicked.emit(this.buildPick(agent));\n }\n\n public StartCall(): void {\n const agent = this.SelectedAgent;\n if (agent) {\n this.AgentPicked.emit(this.buildPick(agent));\n }\n }\n\n public Cancel(): void {\n this.Cancelled.emit();\n }\n\n /** Dismiss when the user clicks anywhere outside the popover. (The phone\n * button that opens it stops propagation, so the opening click never\n * reaches this handler.) */\n @HostListener('document:click', ['$event'])\n public OnDocumentClick(event: MouseEvent): void {\n if (!this.elementRef.nativeElement.contains(event.target as Node)) {\n this.Cancelled.emit();\n }\n }\n\n @HostListener('document:keydown.escape')\n public OnEscape(): void {\n this.Cancelled.emit();\n }\n\n /**\n * Assembles the emitted pick. The model preference is hard-gated on the\n * authorization here (defense in depth — unauthorized users never see the selector,\n * so `SelectedModelId` should already be null).\n */\n private buildPick(agent: MJAIAgentEntityExtended): RealtimeAgentPick {\n return {\n Agent: agent,\n PreferredModelId: this.CanOverrideSessionConfig ? this.SelectedModelId : null,\n PreferredVoice: this.CanOverrideSessionConfig ? this.SelectedVoiceId : null,\n CoAgentId: this.SelectedCoAgentId\n };\n }\n\n private isDefault(agent: MJAIAgentEntityExtended): boolean {\n return !!this.DefaultAgentId && UUIDsEqual(agent.ID, this.DefaultAgentId);\n }\n\n private findAgent(id: string): MJAIAgentEntityExtended | null {\n return this.Agents.find(a => UUIDsEqual(a.ID, id)) ?? null;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"realtime-agent-picker.component.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-agent-picker.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n HostListener,\n Input,\n OnInit,\n Output,\n ViewChild,\n AfterViewInit,\n inject,\n} from '@angular/core';\nimport type { MJAIAgentEntityExtended } from '@memberjunction/ai-core-plus';\nimport { MJButtonDirective } from '@memberjunction/ng-ui-components';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { UserInfoEngine } from '@memberjunction/core-entities';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { REALTIME_ADVANCED_SESSION_CONTROLS, UserHoldsAuthorization } from '../../services/user-authorization';\nimport {\n BuildRealtimeModelOptions,\n ConstrainTargetsToPairings,\n DefaultPairedTargetId,\n LoadCoAgentPairings,\n RealtimeModelOption,\n RealtimePairedAgentRow,\n} from '../../services/realtime-pairing';\nimport { GraphQLLiveKitClient, GraphQLDataProvider, RealtimeModelVoices, RealtimeVoiceOption } from '@memberjunction/graphql-dataprovider';\n\n/**\n * The user's confirmed choice from the realtime picker: the agent to call, an optional\n * EXPLICIT realtime model (`null` = \"Auto (recommended)\", i.e. let the server pick —\n * always `null` for users without the `Realtime: Advanced Session Controls`\n * authorization, who never see the model selector), and an optional EXPLICIT co-agent\n * (`null` = the server's co-agent resolution chain).\n */\nexport interface RealtimeAgentPick {\n /** The agent the voice call should front. */\n Agent: MJAIAgentEntityExtended;\n /** Explicit realtime model id, or `null` for the server's automatic selection. */\n PreferredModelId: string | null;\n /** Explicit provider-native voice id (e.g. `echo`), or `null` for the configured/default voice. */\n PreferredVoice: string | null;\n /** Explicit co-agent id (`MJ: AI Agents.ID`, Realtime type), or `null` for the server's resolution chain. */\n CoAgentId: string | null;\n /** Whether the user consented to recording this call (mic + agent audio). */\n RecordingConsent: boolean;\n}\n\n/** `MJ: User Settings` key for the per-user \"record this call\" consent toggle (string `'true'`/`'false'`). */\nconst RECORDING_CONSENT_KEY = 'mj.realtimeVoice.recordingConsent.v1';\n\n/**\n * Compact anchored popover that lets the user choose WHICH agent a realtime\n * voice call should front — shown by {@link MessageInputComponent} when the\n * phone button is clicked on a conversation with **no prior agent\n * participation** (new / empty conversation), and on demand via the caret\n * button next to the phone (any conversation), where it doubles as the way\n * to pick a specific **co-agent** (the Realtime-type agent that voices the\n * call) and — for authorized users — a specific **voice model**. The plain\n * phone click on an existing conversation keeps its friction-free \"call the\n * resolved agent immediately\" behavior.\n *\n * Mostly dumb: the host supplies the agent list (the same cached set the\n * @mention autocomplete / routing logic uses), the Realtime-type co-agent\n * candidates (filtered from that same set), and the defaults to preselect;\n * the picker emits the user's choice. The data it loads itself:\n * - the compact \"Voice model\" option list (active Realtime models via a\n * narrow RunView) — loaded and rendered ONLY when the current user holds\n * the `Realtime: Advanced Session Controls` authorization (pure UX\n * disclosure; the server enforces the authorization on the mint), and\n * - the chosen co-agent's pairing rows (`MJ: AI Agent Co Agents`, Active 'CoAgent'-type rows): a\n * co-agent with pairing rows may only front its paired targets, so the\n * agent list constrains to those rows (Sequence order) with the IsDefault\n * row preselected; a co-agent with zero rows is universal and the list is\n * untouched.\n *\n * It does NOT persist anything (the host persists the co-agent preference\n * via `UserInfoEngine`; `mj-conversation-agent-picker` pins\n * `MJConversationEntity.DefaultAgentID` — different jobs, which is why this\n * is a separate component).\n *\n * Anchors itself bottom-right above the composer — the host's\n * `.message-input-wrapper` is `position: relative`.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-agent-picker',\n imports: [MJButtonDirective],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"mj-voice-picker\" (click)=\"$event.stopPropagation()\">\n <div class=\"mj-voice-picker__header\">\n <i class=\"fa-solid fa-phone\"></i>\n <span>Start a voice call with…</span>\n </div>\n @if (ShowCoAgentSelect) {\n <div class=\"mj-voice-picker__select-row\">\n <label class=\"mj-voice-picker__select-label\" for=\"mjRealtimeCoAgentSelect\">\n <i class=\"fa-solid fa-headset\"></i>\n <span>Co-agent</span>\n </label>\n <select\n #coAgentSelect\n id=\"mjRealtimeCoAgentSelect\"\n class=\"mj-voice-picker__select\"\n [value]=\"SelectedCoAgentId ?? ''\"\n (change)=\"OnCoAgentChange(coAgentSelect.value)\">\n <option value=\"\">Auto (recommended)</option>\n @for (coAgent of CoAgents; track coAgent.ID) {\n <option [value]=\"coAgent.ID\">{{ coAgent.Name }}</option>\n }\n </select>\n </div>\n }\n <div class=\"mj-voice-picker__search\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <input\n #searchInput\n type=\"text\"\n placeholder=\"Search agents\"\n [value]=\"SearchText\"\n (input)=\"OnSearchInput(searchInput.value)\"\n (keydown.enter)=\"StartCall()\"\n (keydown.arrowdown)=\"MoveSelection(1); $event.preventDefault()\"\n (keydown.arrowup)=\"MoveSelection(-1); $event.preventDefault()\" />\n </div>\n <div class=\"mj-voice-picker__list\">\n @if (FilteredAgents.length === 0) {\n <div class=\"mj-voice-picker__empty\">{{ IsConstrainedByPairings ? 'No paired agents available' : 'No matching agents' }}</div>\n } @else {\n @for (agent of FilteredAgents; track agent.ID) {\n <button\n type=\"button\"\n class=\"mj-voice-picker__item\"\n [class.mj-voice-picker__item--selected]=\"IsSelected(agent)\"\n [title]=\"agent.Description || agent.Name\"\n (click)=\"Select(agent)\"\n (dblclick)=\"Pick(agent)\">\n <i [class]=\"IconClassFor(agent)\"></i>\n <span class=\"mj-voice-picker__item-name\">{{ agent.Name }}</span>\n @if (IsDefaultChoice(agent)) {\n <span class=\"mj-voice-picker__default-badge\">default</span>\n }\n </button>\n }\n }\n </div>\n @if (CanOverrideSessionConfig && Models.length > 0) {\n <div class=\"mj-voice-picker__select-row mj-voice-picker__select-row--model\">\n <label class=\"mj-voice-picker__select-label\" for=\"mjRealtimeModelSelect\">\n <i class=\"fa-solid fa-microchip\"></i>\n <span>Voice model</span>\n </label>\n <select\n #modelSelect\n id=\"mjRealtimeModelSelect\"\n class=\"mj-voice-picker__select\"\n [value]=\"SelectedModelId ?? ''\"\n (change)=\"OnModelChange(modelSelect.value)\">\n <option value=\"\">Auto (recommended)</option>\n @for (model of Models; track model.ID) {\n <option [value]=\"model.ID\">{{ model.Name }}</option>\n }\n </select>\n </div>\n @if (SelectedModelVoices.length) {\n <div class=\"mj-voice-picker__select-row mj-voice-picker__select-row--model\">\n <label class=\"mj-voice-picker__select-label\" for=\"mjRealtimeVoiceSelect\">\n <i class=\"fa-solid fa-waveform-lines\"></i>\n <span>Voice</span>\n </label>\n <select\n #voiceSelect\n id=\"mjRealtimeVoiceSelect\"\n class=\"mj-voice-picker__select\"\n [value]=\"SelectedVoiceId ?? ''\"\n (change)=\"OnVoiceChange(voiceSelect.value)\">\n <option value=\"\">Default</option>\n @for (v of SelectedModelVoices; track v.ID) {\n <option [value]=\"v.ID\">{{ v.Name }}</option>\n }\n </select>\n </div>\n }\n }\n <div class=\"mj-voice-picker__record-row\">\n <span class=\"mj-voice-picker__record-label\">\n <i class=\"fa-solid fa-microphone\"></i>\n <span class=\"mj-voice-picker__record-copy\">\n Record this call\n <small>Audio stored securely</small>\n </span>\n </span>\n <label class=\"mj-voice-picker__switch\">\n <input\n type=\"checkbox\"\n [checked]=\"RecordingConsent\"\n (change)=\"OnRecordingConsentChange($any($event.target).checked)\"\n aria-label=\"Record this call (audio stored securely)\" />\n <span class=\"mj-voice-picker__switch-track\"></span>\n </label>\n </div>\n <div class=\"mj-voice-picker__footer\">\n <button mjButton variant=\"primary\" size=\"sm\" [disabled]=\"!SelectedAgent\" (click)=\"StartCall()\">\n <i class=\"fa-solid fa-phone\"></i> Start\n </button>\n <button mjButton variant=\"outline\" size=\"sm\" (click)=\"Cancel()\">Cancel</button>\n </div>\n </div>\n `,\n styles: [`\n :host {\n /* Rendered inside a body-level CDK connected overlay (see message-input) — CDK\n owns the positioning + z-index, so the host is just a plain block. The height\n cap keeps the popover from growing past the viewport; the agent list inside\n scrolls when content exceeds it. CDK's push keeps it on-screen, and because\n it lives at the body level it can never be clipped by the chat overlay border. */\n display: block;\n max-height: min(440px, calc(100vh - 24px));\n }\n .mj-voice-picker {\n width: 300px;\n max-width: calc(100vw - 24px);\n display: flex; flex-direction: column;\n /* Match the host cap so the inner flex column knows its bound and lets the agent\n list ('mj-voice-picker__list') take the remaining space + scroll. */\n max-height: min(440px, calc(100vh - 120px));\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);\n overflow: hidden;\n }\n .mj-voice-picker__header {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 12px 8px;\n font-size: 13px; font-weight: 600;\n color: var(--mj-text-primary);\n }\n .mj-voice-picker__header i { color: var(--mj-brand-primary); }\n .mj-voice-picker__search {\n display: flex; align-items: center; gap: 8px;\n margin: 0 12px 8px;\n padding: 0 10px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n }\n .mj-voice-picker__search i { font-size: 12px; color: var(--mj-text-muted); }\n .mj-voice-picker__search input {\n flex: 1; min-width: 0;\n padding: 7px 0;\n background: transparent; border: none; outline: none;\n font-size: 13px; color: var(--mj-text-primary);\n }\n .mj-voice-picker__search input::placeholder { color: var(--mj-text-disabled); }\n .mj-voice-picker__search:focus-within { border-color: var(--mj-border-focus); }\n .mj-voice-picker__list {\n /* The agent list is the flexible region: it scrolls internally and gives way\n first when the whole popup is capped to the overlay height. min-height:0 lets\n it actually shrink inside the flex column; the 220px max keeps it tidy when\n there's plenty of room. */\n flex: 1 1 auto;\n min-height: 0;\n max-height: 220px; overflow-y: auto;\n border-top: 1px solid var(--mj-border-subtle);\n border-bottom: 1px solid var(--mj-border-subtle);\n padding: 4px 0;\n }\n /* Keep the chrome around the list from collapsing when the popup is height-capped. */\n .mj-voice-picker__header,\n .mj-voice-picker__search,\n .mj-voice-picker__select-row,\n .mj-voice-picker__record-row,\n .mj-voice-picker__footer { flex-shrink: 0; }\n .mj-voice-picker__item {\n display: flex; align-items: center; gap: 8px; width: 100%;\n padding: 7px 12px;\n background: transparent; border: none; cursor: pointer;\n color: var(--mj-text-primary); font-size: 13px; text-align: left;\n }\n .mj-voice-picker__item i { width: 16px; text-align: center; color: var(--mj-text-secondary); }\n .mj-voice-picker__item:hover { background: var(--mj-bg-surface-hover); }\n .mj-voice-picker__item--selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n .mj-voice-picker__item--selected i { color: var(--mj-brand-primary); }\n .mj-voice-picker__item-name {\n flex: 1; min-width: 0;\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n }\n .mj-voice-picker__default-badge {\n flex-shrink: 0;\n padding: 1px 6px;\n border-radius: 999px;\n font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n }\n .mj-voice-picker__empty {\n padding: 12px; font-size: 12px; color: var(--mj-text-muted); text-align: center;\n }\n .mj-voice-picker__select-row {\n display: flex; align-items: center; gap: 8px;\n padding: 0 12px 8px;\n }\n .mj-voice-picker__select-row--model {\n padding: 8px 12px 0;\n }\n .mj-voice-picker__select-label {\n display: flex; align-items: center; gap: 6px;\n flex-shrink: 0;\n font-size: 12px; color: var(--mj-text-secondary);\n }\n .mj-voice-picker__select-label i { font-size: 11px; color: var(--mj-text-muted); }\n .mj-voice-picker__select {\n flex: 1; min-width: 0;\n padding: 5px 8px;\n font-size: 12px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n outline: none;\n }\n .mj-voice-picker__select:focus { border-color: var(--mj-border-focus); }\n .mj-voice-picker__record-row {\n display: flex; align-items: center; justify-content: space-between; gap: 10px;\n margin: 10px 12px 2px;\n padding: 10px 0 2px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n .mj-voice-picker__record-label {\n display: flex; align-items: center; gap: 8px;\n font-size: 12px; color: var(--mj-text-secondary);\n }\n .mj-voice-picker__record-label > i { font-size: 12px; color: var(--mj-text-muted); }\n .mj-voice-picker__record-copy { display: flex; flex-direction: column; line-height: 1.3; }\n .mj-voice-picker__record-copy small { font-size: 10px; color: var(--mj-text-muted); }\n .mj-voice-picker__switch { position: relative; flex-shrink: 0; display: inline-flex; cursor: pointer; }\n .mj-voice-picker__switch input {\n position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer;\n }\n .mj-voice-picker__switch-track {\n position: relative; width: 34px; height: 18px; border-radius: 999px;\n background: var(--mj-border-strong); transition: background 150ms ease;\n }\n .mj-voice-picker__switch-track::after {\n content: ''; position: absolute; top: 2px; left: 2px;\n width: 14px; height: 14px; border-radius: 50%;\n background: var(--mj-bg-surface); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);\n transition: transform 150ms ease;\n }\n .mj-voice-picker__switch input:checked + .mj-voice-picker__switch-track { background: var(--mj-brand-primary); }\n .mj-voice-picker__switch input:checked + .mj-voice-picker__switch-track::after { transform: translateX(16px); }\n .mj-voice-picker__switch input:focus-visible + .mj-voice-picker__switch-track {\n outline: 2px solid var(--mj-border-focus); outline-offset: 2px;\n }\n @media (prefers-reduced-motion: reduce) {\n .mj-voice-picker__switch-track, .mj-voice-picker__switch-track::after { transition: none; }\n }\n .mj-voice-picker__footer {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 12px;\n }\n `]\n})\nexport class RealtimeAgentPickerComponent extends BaseAngularComponent implements OnInit, AfterViewInit {\n /** Agents the user can call — same cached set the @mention / routing logic uses. */\n @Input() Agents: MJAIAgentEntityExtended[] = [];\n\n /** The agent the default resolution would pick — preselected and listed first. */\n @Input() DefaultAgentId: string | null = null;\n\n /**\n * The ACTIVE Realtime-type co-agent candidates the user can run (host-filtered from\n * the same cached, run-permission-filtered agent set as {@link Agents}). The co-agent\n * selector renders only when MORE THAN ONE candidate exists — with zero or one\n * there's nothing meaningful to choose and the server's resolution chain applies.\n */\n @Input() CoAgents: MJAIAgentEntityExtended[] = [];\n\n /**\n * The user's persisted co-agent preference (host-loaded via `UserInfoEngine`) —\n * preselected in the co-agent selector when it's still a valid candidate.\n */\n @Input() DefaultCoAgentId: string | null = null;\n\n /** Emitted with the chosen agent + optional explicit voice model / co-agent when the user confirms. */\n @Output() AgentPicked = new EventEmitter<RealtimeAgentPick>();\n\n /** Emitted when the user dismisses without starting a call. */\n @Output() Cancelled = new EventEmitter<void>();\n\n @ViewChild('searchInput') private searchInput?: ElementRef<HTMLInputElement>;\n\n public SearchText = '';\n public SelectedAgentId: string | null = null;\n\n /** Active Realtime models the model selector offers (loaded only for authorized users). */\n public Models: RealtimeModelOption[] = [];\n\n /** The explicitly chosen voice model id, or `null` for \"Auto (recommended)\" (the default). */\n public SelectedModelId: string | null = null;\n\n /** Active Realtime models + their voices (for the voice selector); loaded only for authorized users. */\n public VoiceModels: RealtimeModelVoices[] = [];\n\n /** The explicitly chosen voice id, or `null` for the configured/default voice. */\n public SelectedVoiceId: string | null = null;\n\n /** Voices for the currently-selected model (empty when no model picked or it declares none). */\n public get SelectedModelVoices(): RealtimeVoiceOption[] {\n return this.VoiceModels.find((m) => UUIDsEqual(m.ModelID, this.SelectedModelId))?.Voices ?? [];\n }\n\n /** The explicitly chosen co-agent id, or `null` for \"Auto (recommended)\" (the server's chain). */\n public SelectedCoAgentId: string | null = null;\n\n /**\n * Whether the user has opted to record this call (mic + agent audio). Loaded from the\n * per-user persisted preference (`mj.realtimeVoice.recordingConsent.v1`) on init and\n * persisted cross-device on change. Defaults to off.\n */\n public RecordingConsent = false;\n\n /**\n * Whether the current user holds the `Realtime: Advanced Session Controls`\n * authorization. Gates the voice-model selector (and any future config-override\n * controls) — pure disclosure; the server enforces the authorization on the mint.\n */\n public CanOverrideSessionConfig = false;\n\n /** The selected co-agent's pairing rows; empty = universal co-agent (no constraint). */\n public Pairings: RealtimePairedAgentRow[] = [];\n\n // Template helper — expose the shared UUID comparator to the view.\n public readonly UUIDsEqual = UUIDsEqual;\n\n private readonly cdr = inject(ChangeDetectorRef);\n private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n /** Monotonic guard so a stale pairing load can't clobber a newer co-agent choice. */\n private pairingLoadToken = 0;\n\n /** Co-agent selector visibility: only when there is a real choice to make. */\n public get ShowCoAgentSelect(): boolean {\n return this.CoAgents.length > 1;\n }\n\n /** True while the agent list is constrained to the selected co-agent's paired targets. */\n public get IsConstrainedByPairings(): boolean {\n return this.Pairings.length > 0;\n }\n\n public ngOnInit(): void {\n const initial = this.DefaultAgentId && this.findAgent(this.DefaultAgentId)\n ? this.DefaultAgentId\n : this.FilteredAgents[0]?.ID ?? null;\n this.SelectedAgentId = initial;\n this.CanOverrideSessionConfig = UserHoldsAuthorization(\n this.ProviderToUse?.CurrentUser,\n REALTIME_ADVANCED_SESSION_CONTROLS,\n this.ProviderToUse\n );\n if (this.CanOverrideSessionConfig) {\n void this.loadVoiceModels();\n }\n // Preselect the persisted co-agent preference when it's still a valid candidate.\n if (this.DefaultCoAgentId && this.CoAgents.some(a => UUIDsEqual(a.ID, this.DefaultCoAgentId))) {\n this.SelectedCoAgentId = this.DefaultCoAgentId;\n void this.reloadPairings();\n }\n this.RecordingConsent = this.readPersistedRecordingConsent();\n }\n\n /** Reads the per-user recording-consent preference (defensive: any failure → off). */\n private readPersistedRecordingConsent(): boolean {\n try {\n return UserInfoEngine.Instance.GetSetting(RECORDING_CONSENT_KEY) === 'true';\n } catch {\n return false;\n }\n }\n\n /** Records + persists (cross-device, debounced) the user's recording-consent choice. */\n public OnRecordingConsentChange(checked: boolean): void {\n this.RecordingConsent = checked;\n try {\n UserInfoEngine.Instance.SetSettingDebounced(RECORDING_CONSENT_KEY, String(checked));\n } catch (error) {\n console.warn('[RealtimeAgentPicker] Failed to persist recording consent:', error);\n }\n this.cdr.markForCheck();\n }\n\n /**\n * Loads the \"Voice model\" options: active models whose type is `Realtime`, filtered from\n * {@link AIEngineBase}'s already-cached `Models` (provider-scoped engine instance, lazy\n * `Config` — no RunView round-trip). Called ONLY for users who hold the\n * advanced-session-controls authorization. Tolerant — a failure simply leaves\n * the selector hidden (the server's automatic selection still applies).\n */\n private async loadVoiceModels(): Promise<void> {\n try {\n const engine = AIEngineBase.GetProviderInstance<AIEngineBase>(this.ProviderToUse, AIEngineBase) as AIEngineBase;\n await engine.Config(false, undefined, this.ProviderToUse);\n this.Models = BuildRealtimeModelOptions(engine.Models ?? []);\n } catch (error) {\n console.error('[RealtimeAgentPicker] Failed to load realtime models:', error);\n this.Models = [];\n }\n // Voices come from the driver via a server query (the cached models carry no voice list).\n try {\n const client = new GraphQLLiveKitClient(this.ProviderToUse as unknown as GraphQLDataProvider);\n this.VoiceModels = await client.GetRealtimeModelVoices();\n } catch (error) {\n console.error('[RealtimeAgentPicker] Failed to load realtime voices:', error);\n this.VoiceModels = [];\n }\n this.cdr.markForCheck();\n }\n\n /** Records the voice-model choice (`''` = Auto → `null`); clears the voice so it can't outlive a switch. */\n public OnModelChange(value: string): void {\n this.SelectedModelId = value && value.length > 0 ? value : null;\n this.SelectedVoiceId = null;\n this.cdr.markForCheck();\n }\n\n /** Records the voice choice (`''` = default → `null`). */\n public OnVoiceChange(value: string): void {\n this.SelectedVoiceId = value && value.length > 0 ? value : null;\n this.cdr.markForCheck();\n }\n\n /** Records the co-agent choice (`''` = Auto → `null`) and refreshes the pairing constraint. */\n public OnCoAgentChange(value: string): void {\n this.SelectedCoAgentId = value && value.length > 0 ? value : null;\n void this.reloadPairings();\n }\n\n /**\n * Loads the selected co-agent's pairing rows and re-applies the target constraint:\n * with rows present, the agent list narrows to the paired targets (Sequence order)\n * and the IsDefault row's target is preselected; with zero rows (or Auto co-agent)\n * the list returns to the unconstrained default. Guarded against stale loads when\n * the user changes co-agents quickly.\n */\n private async reloadPairings(): Promise<void> {\n const token = ++this.pairingLoadToken;\n const coAgentId = this.SelectedCoAgentId;\n const pairings = coAgentId ? await LoadCoAgentPairings(this.ProviderToUse, coAgentId) : [];\n if (token !== this.pairingLoadToken) {\n return; // a newer co-agent choice superseded this load\n }\n this.Pairings = pairings;\n this.ensureSelectionVisible();\n this.cdr.markForCheck();\n }\n\n /**\n * Keeps the target selection coherent after the visible list changes: prefers the\n * pairing default (when constrained), then the host default, then keeps the current\n * selection when still visible, then the first visible row.\n */\n private ensureSelectionVisible(): void {\n const visible = this.FilteredAgents;\n if (this.IsConstrainedByPairings) {\n const pairedDefault = DefaultPairedTargetId(this.Pairings);\n if (pairedDefault && visible.some(a => UUIDsEqual(a.ID, pairedDefault))) {\n this.SelectedAgentId = pairedDefault;\n return;\n }\n }\n if (this.SelectedAgentId && visible.some(a => UUIDsEqual(a.ID, this.SelectedAgentId))) {\n return; // current selection still valid\n }\n if (this.DefaultAgentId && visible.some(a => UUIDsEqual(a.ID, this.DefaultAgentId))) {\n this.SelectedAgentId = this.DefaultAgentId;\n return;\n }\n this.SelectedAgentId = visible[0]?.ID ?? null;\n }\n\n public ngAfterViewInit(): void {\n // Microtask so focus lands after the popover renders without\n // triggering ExpressionChangedAfterItHasBeenChecked.\n Promise.resolve().then(() => this.searchInput?.nativeElement.focus());\n }\n\n /**\n * The visible target list: pairing-constrained first (a co-agent WITH pairing rows may\n * only front its paired targets, kept in pairing Sequence order), then search-filtered.\n * Unconstrained lists keep the default-first + alphabetical ordering.\n */\n public get FilteredAgents(): MJAIAgentEntityExtended[] {\n const base = ConstrainTargetsToPairings(this.Agents, this.Pairings);\n const needle = this.SearchText.trim().toLowerCase();\n const filtered = base.filter(a => !needle || (a.Name ?? '').toLowerCase().includes(needle));\n if (this.IsConstrainedByPairings) {\n return filtered; // pairing Sequence order is the canonical order\n }\n return filtered.sort((a, b) => {\n const aDefault = this.isDefault(a) ? 0 : 1;\n const bDefault = this.isDefault(b) ? 0 : 1;\n if (aDefault !== bDefault) return aDefault - bDefault;\n return (a.Name ?? '').localeCompare(b.Name ?? '');\n });\n }\n\n public get SelectedAgent(): MJAIAgentEntityExtended | null {\n return this.SelectedAgentId ? this.findAgent(this.SelectedAgentId) : null;\n }\n\n public IsSelected(agent: MJAIAgentEntityExtended): boolean {\n return !!this.SelectedAgentId && UUIDsEqual(agent.ID, this.SelectedAgentId);\n }\n\n /**\n * Whether `agent` carries the \"default\" badge: under a pairing constraint that's the\n * co-agent's IsDefault target; otherwise the host-resolved default agent.\n */\n public IsDefaultChoice(agent: MJAIAgentEntityExtended): boolean {\n if (this.IsConstrainedByPairings) {\n const pairedDefault = DefaultPairedTargetId(this.Pairings);\n return !!pairedDefault && UUIDsEqual(agent.ID, pairedDefault);\n }\n return this.isDefault(agent);\n }\n\n public IconClassFor(agent: MJAIAgentEntityExtended): string {\n return agent.IconClass?.trim() || 'fa-solid fa-robot';\n }\n\n public OnSearchInput(value: string): void {\n this.SearchText = value;\n // Keep the selection on a visible row.\n const visible = this.FilteredAgents;\n if (!visible.some(a => this.IsSelected(a))) {\n this.SelectedAgentId = visible[0]?.ID ?? null;\n }\n this.cdr.markForCheck();\n }\n\n /** Arrow-key navigation through the filtered list. */\n public MoveSelection(delta: number): void {\n const visible = this.FilteredAgents;\n if (visible.length === 0) return;\n const currentIndex = visible.findIndex(a => this.IsSelected(a));\n const nextIndex = currentIndex < 0\n ? 0\n : Math.min(visible.length - 1, Math.max(0, currentIndex + delta));\n this.SelectedAgentId = visible[nextIndex].ID;\n this.cdr.markForCheck();\n }\n\n public Select(agent: MJAIAgentEntityExtended): void {\n this.SelectedAgentId = agent.ID;\n this.cdr.markForCheck();\n }\n\n /** Confirm a specific agent immediately (double-click shortcut). */\n public Pick(agent: MJAIAgentEntityExtended): void {\n this.AgentPicked.emit(this.buildPick(agent));\n }\n\n public StartCall(): void {\n const agent = this.SelectedAgent;\n if (agent) {\n this.AgentPicked.emit(this.buildPick(agent));\n }\n }\n\n public Cancel(): void {\n this.Cancelled.emit();\n }\n\n /** Dismiss when the user clicks anywhere outside the popover. (The phone\n * button that opens it stops propagation, so the opening click never\n * reaches this handler.) */\n @HostListener('document:click', ['$event'])\n public OnDocumentClick(event: MouseEvent): void {\n if (!this.elementRef.nativeElement.contains(event.target as Node)) {\n this.Cancelled.emit();\n }\n }\n\n @HostListener('document:keydown.escape')\n public OnEscape(): void {\n this.Cancelled.emit();\n }\n\n /**\n * Assembles the emitted pick. The model preference is hard-gated on the\n * authorization here (defense in depth — unauthorized users never see the selector,\n * so `SelectedModelId` should already be null).\n */\n private buildPick(agent: MJAIAgentEntityExtended): RealtimeAgentPick {\n return {\n Agent: agent,\n PreferredModelId: this.CanOverrideSessionConfig ? this.SelectedModelId : null,\n PreferredVoice: this.CanOverrideSessionConfig ? this.SelectedVoiceId : null,\n CoAgentId: this.SelectedCoAgentId,\n RecordingConsent: this.RecordingConsent\n };\n }\n\n private isDefault(agent: MJAIAgentEntityExtended): boolean {\n return !!this.DefaultAgentId && UUIDsEqual(agent.ID, this.DefaultAgentId);\n }\n\n private findAgent(id: string): MJAIAgentEntityExtended | null {\n return this.Agents.find(a => UUIDsEqual(a.ID, id)) ?? null;\n }\n}\n"]}
|
|
@@ -15,7 +15,7 @@ import { RealtimeAudioActivity } from '@memberjunction/ai-realtime-client';
|
|
|
15
15
|
* rule unit-tests without Web Audio or a browser clock.
|
|
16
16
|
*/
|
|
17
17
|
/** Who is audibly speaking right now (drives the orb/EQ direction color). */
|
|
18
|
-
export type
|
|
18
|
+
export type RealtimeDirection = 'agent' | 'user' | 'none';
|
|
19
19
|
/** One smoothed, render-ready visual frame. */
|
|
20
20
|
export interface RealtimeAudioVisualFrame {
|
|
21
21
|
/** Smoothed agent-output level, 0..1. */
|
|
@@ -25,7 +25,7 @@ export interface RealtimeAudioVisualFrame {
|
|
|
25
25
|
/** Smoothed spectrum bins (length {@link AUDIO_VISUAL_BIN_COUNT}) of the dominant direction. */
|
|
26
26
|
Bins: number[];
|
|
27
27
|
/** Resolved speaking direction (hysteresis-stable). */
|
|
28
|
-
Direction:
|
|
28
|
+
Direction: RealtimeDirection;
|
|
29
29
|
}
|
|
30
30
|
/** Number of EQ bars the hero renders (matches the meter's bin count). */
|
|
31
31
|
export declare const AUDIO_VISUAL_BIN_COUNT = 9;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-audio-visuals.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-audio-visuals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAE3E;;;;;;;;;;;;;;GAcG;AAEH,6EAA6E;AAC7E,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"realtime-audio-visuals.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-audio-visuals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAE3E;;;;;;;;;;;;;;GAcG;AAEH,6EAA6E;AAC7E,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1D,+CAA+C;AAC/C,MAAM,WAAW,wBAAwB;IACvC,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,uDAAuD;IACvD,SAAS,EAAE,iBAAiB,CAAC;CAC9B;AAED,0EAA0E;AAC1E,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAE1C,kGAAkG;AAClG,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,0FAA0F;AAC1F,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,sBAAsB,QAAQ,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAK7D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAY,EAAE,KAAK,GAAE,MAAa,GAAG,MAAM,CAI9G;AAED;;;;GAIG;AACH,qBAAa,2BAA2B;IACtC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,IAAI,CAA+D;IAC3E,OAAO,CAAC,SAAS,CAA6B;IAC9C,oFAAoF;IACpF,OAAO,CAAC,eAAe,CAAK;IAE5B,0DAA0D;IACnD,KAAK,IAAI,IAAI;IAQpB;;;;;OAKG;IACI,IAAI,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI;IAmB9F;;;;OAIG;IACH,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,UAAU;IASlB;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;CA4BzB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-audio-visuals.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-audio-visuals.ts"],"names":[],"mappings":"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","sourcesContent":["import { RealtimeAudioActivity } from '@memberjunction/ai-realtime-client';\n\n/**\n * @fileoverview AUDIO-REACTIVE VISUAL SMOOTHING for the call overlay — the framework-free\n * math between raw per-frame {@link RealtimeAudioActivity} samples and the CSS variables\n * that make the hero orb vibrate like a speaker cone and the EQ render a true spectrum.\n *\n * Raw analyser levels are jittery; rendering them directly strobes. This module applies:\n * - **Attack/decay envelope smoothing** ({@link SmoothLevel}) — fast attack so speech\n * onset feels instant, slow decay so the cone \"rings down\" instead of snapping shut.\n * - **Direction resolution with hysteresis** — who is audibly speaking (`agent` / `user` /\n * `none`) with a presence floor and a hold window, so the direction color never\n * flickers across syllable gaps.\n *\n * Owned by the overlay's requestAnimationFrame loop (outside Angular); kept pure so every\n * rule unit-tests without Web Audio or a browser clock.\n */\n\n/** Who is audibly speaking right now (drives the orb/EQ direction color). */\nexport type RealtimeVoiceDirection = 'agent' | 'user' | 'none';\n\n/** One smoothed, render-ready visual frame. */\nexport interface RealtimeAudioVisualFrame {\n /** Smoothed agent-output level, 0..1. */\n OutputLevel: number;\n /** Smoothed user-mic level, 0..1. */\n InputLevel: number;\n /** Smoothed spectrum bins (length {@link AUDIO_VISUAL_BIN_COUNT}) of the dominant direction. */\n Bins: number[];\n /** Resolved speaking direction (hysteresis-stable). */\n Direction: RealtimeVoiceDirection;\n}\n\n/** Number of EQ bars the hero renders (matches the meter's bin count). */\nexport const AUDIO_VISUAL_BIN_COUNT = 9;\n\n/** Levels below this are treated as silence for direction purposes. */\nexport const AUDIO_PRESENCE_FLOOR = 0.045;\n\n/** How long a direction is HELD after its audio drops below the floor (syllable-gap proofing). */\nexport const AUDIO_DIRECTION_HOLD_MS = 280;\n\n/** The factor by which the other side must dominate to steal the direction mid-speech. */\nexport const AUDIO_DIRECTION_STEAL_FACTOR = 1.15;\n\n/**\n * NOISE GATES (per direction): raw analyser levels at/below the gate render as TRUE\n * silence — without this, an idle microphone's room-noise/auto-gain floor keeps the EQ\n * dancing and the direction stuck on \"user\" while nobody is speaking. The mic gate sits\n * a touch above the output gate (playback silence is actual zero; mic silence isn't), but\n * NOT so high it swallows normal speech: 0.08 over-gated — typical Mac-mic normalized speech\n * peaks well under it, so the meter read silence the whole time the user was talking. 0.045\n * (≈ the presence floor) suppresses idle room-noise while letting real speech drive the EQ.\n */\nexport const AUDIO_OUTPUT_NOISE_GATE = 0.03;\nexport const AUDIO_INPUT_NOISE_GATE = 0.045;\n\n/**\n * Soft-knee noise gate: at/below `gate` → 0; above it the remaining range rescales to\n * 0..1 (so the gate never visibly \"clips\" the bottom off real speech). Pure.\n */\nexport function GateLevel(level: number, gate: number): number {\n if (!Number.isFinite(level) || level <= gate) {\n return 0;\n }\n return Math.min(1, (level - gate) / (1 - gate));\n}\n\n/**\n * One smoothing step: fast attack (speech onset reads instantly), slow decay (the level\n * rings down like a speaker cone instead of snapping). Pure.\n */\nexport function SmoothLevel(previous: number, next: number, attack: number = 0.5, decay: number = 0.12): number {\n const factor = next > previous ? attack : decay;\n const value = previous + (next - previous) * factor;\n return Math.min(1, Math.max(0, value));\n}\n\n/**\n * Per-overlay smoothing state machine. Feed it one raw {@link RealtimeAudioActivity}\n * sample per animation frame via {@link Next}; render the returned frame. `null` in →\n * `null` out (the driver attached no meters — the host keeps turn-state visuals).\n */\nexport class RealtimeAudioVisualSmoother {\n private outputLevel = 0;\n private inputLevel = 0;\n private bins: number[] = new Array<number>(AUDIO_VISUAL_BIN_COUNT).fill(0);\n private direction: RealtimeVoiceDirection = 'none';\n /** Last time (ms) the current direction's level was at/above the presence floor. */\n private directionHeldAt = 0;\n\n /** Resets all smoothing state (call between sessions). */\n public Reset(): void {\n this.outputLevel = 0;\n this.inputLevel = 0;\n this.bins = new Array<number>(AUDIO_VISUAL_BIN_COUNT).fill(0);\n this.direction = 'none';\n this.directionHeldAt = 0;\n }\n\n /**\n * Advances the smoother with one raw sample.\n * @param raw The client's current audio activity (`null` = no metering capability).\n * @param nowMs A monotonic clock reading (e.g. `performance.now()`).\n * @returns The render-ready frame, or `null` when un-metered.\n */\n public Next(raw: RealtimeAudioActivity | null, nowMs: number): RealtimeAudioVisualFrame | null {\n if (!raw) {\n return null;\n }\n // Gate BEFORE smoothing: silence is true zero, the decay still rings down smoothly.\n const gatedOut = GateLevel(raw.OutputLevel ?? 0, AUDIO_OUTPUT_NOISE_GATE);\n const gatedIn = GateLevel(raw.InputLevel ?? 0, AUDIO_INPUT_NOISE_GATE);\n this.outputLevel = SmoothLevel(this.outputLevel, gatedOut);\n this.inputLevel = SmoothLevel(this.inputLevel, gatedIn);\n this.smoothBins(this.pickRawBins(raw, gatedOut, gatedIn));\n this.resolveDirection(nowMs);\n return {\n OutputLevel: this.outputLevel,\n InputLevel: this.inputLevel,\n Bins: [...this.bins],\n Direction: this.direction\n };\n }\n\n /**\n * The spectrum follows whichever direction is louder (falling back to whichever\n * exists) — but a side whose GATED level is silence contributes no spectrum at all:\n * an idle mic's room-noise bins must not keep the EQ dancing.\n */\n private pickRawBins(raw: RealtimeAudioActivity, gatedOut: number, gatedIn: number): number[] | null {\n const outBins = gatedOut > 0 ? raw.OutputBins : null;\n const inBins = gatedIn > 0 ? raw.InputBins : null;\n if (outBins && inBins) {\n return this.outputLevel >= this.inputLevel ? outBins : inBins;\n }\n return outBins ?? inBins;\n }\n\n private smoothBins(rawBins: number[] | null): void {\n if (!rawBins) {\n // No spectrum available — decay the bars toward silence.\n this.bins = this.bins.map(b => SmoothLevel(b, 0));\n return;\n }\n this.bins = this.bins.map((prev, i) => SmoothLevel(prev, rawBins[i] ?? 0));\n }\n\n /**\n * Direction rules (hysteresis):\n * - silence adopts nothing; speech from silence adopts the louder side immediately;\n * - a live direction RENEWS its hold while at/above the presence floor;\n * - the other side steals the direction only by dominating ({@link AUDIO_DIRECTION_STEAL_FACTOR});\n * - a direction releases to `none` only after {@link AUDIO_DIRECTION_HOLD_MS} of silence —\n * syllable gaps never flicker the color.\n */\n private resolveDirection(nowMs: number): void {\n const out = this.outputLevel;\n const inp = this.inputLevel;\n const audible = out >= AUDIO_PRESENCE_FLOOR || inp >= AUDIO_PRESENCE_FLOOR;\n const louder: RealtimeVoiceDirection = out >= inp ? 'agent' : 'user';\n\n if (this.direction === 'none') {\n if (audible) {\n this.direction = louder;\n this.directionHeldAt = nowMs;\n }\n return;\n }\n\n const currentLevel = this.direction === 'agent' ? out : inp;\n const otherLevel = this.direction === 'agent' ? inp : out;\n if (currentLevel >= AUDIO_PRESENCE_FLOOR) {\n this.directionHeldAt = nowMs;\n }\n if (otherLevel >= AUDIO_PRESENCE_FLOOR && otherLevel >= currentLevel * AUDIO_DIRECTION_STEAL_FACTOR) {\n this.direction = this.direction === 'agent' ? 'user' : 'agent';\n this.directionHeldAt = nowMs;\n return;\n }\n if (!audible && nowMs - this.directionHeldAt > AUDIO_DIRECTION_HOLD_MS) {\n this.direction = 'none';\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"realtime-audio-visuals.js","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-audio-visuals.ts"],"names":[],"mappings":"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","sourcesContent":["import { RealtimeAudioActivity } from '@memberjunction/ai-realtime-client';\n\n/**\n * @fileoverview AUDIO-REACTIVE VISUAL SMOOTHING for the call overlay — the framework-free\n * math between raw per-frame {@link RealtimeAudioActivity} samples and the CSS variables\n * that make the hero orb vibrate like a speaker cone and the EQ render a true spectrum.\n *\n * Raw analyser levels are jittery; rendering them directly strobes. This module applies:\n * - **Attack/decay envelope smoothing** ({@link SmoothLevel}) — fast attack so speech\n * onset feels instant, slow decay so the cone \"rings down\" instead of snapping shut.\n * - **Direction resolution with hysteresis** — who is audibly speaking (`agent` / `user` /\n * `none`) with a presence floor and a hold window, so the direction color never\n * flickers across syllable gaps.\n *\n * Owned by the overlay's requestAnimationFrame loop (outside Angular); kept pure so every\n * rule unit-tests without Web Audio or a browser clock.\n */\n\n/** Who is audibly speaking right now (drives the orb/EQ direction color). */\nexport type RealtimeDirection = 'agent' | 'user' | 'none';\n\n/** One smoothed, render-ready visual frame. */\nexport interface RealtimeAudioVisualFrame {\n /** Smoothed agent-output level, 0..1. */\n OutputLevel: number;\n /** Smoothed user-mic level, 0..1. */\n InputLevel: number;\n /** Smoothed spectrum bins (length {@link AUDIO_VISUAL_BIN_COUNT}) of the dominant direction. */\n Bins: number[];\n /** Resolved speaking direction (hysteresis-stable). */\n Direction: RealtimeDirection;\n}\n\n/** Number of EQ bars the hero renders (matches the meter's bin count). */\nexport const AUDIO_VISUAL_BIN_COUNT = 9;\n\n/** Levels below this are treated as silence for direction purposes. */\nexport const AUDIO_PRESENCE_FLOOR = 0.045;\n\n/** How long a direction is HELD after its audio drops below the floor (syllable-gap proofing). */\nexport const AUDIO_DIRECTION_HOLD_MS = 280;\n\n/** The factor by which the other side must dominate to steal the direction mid-speech. */\nexport const AUDIO_DIRECTION_STEAL_FACTOR = 1.15;\n\n/**\n * NOISE GATES (per direction): raw analyser levels at/below the gate render as TRUE\n * silence — without this, an idle microphone's room-noise/auto-gain floor keeps the EQ\n * dancing and the direction stuck on \"user\" while nobody is speaking. The mic gate sits\n * a touch above the output gate (playback silence is actual zero; mic silence isn't), but\n * NOT so high it swallows normal speech: 0.08 over-gated — typical Mac-mic normalized speech\n * peaks well under it, so the meter read silence the whole time the user was talking. 0.045\n * (≈ the presence floor) suppresses idle room-noise while letting real speech drive the EQ.\n */\nexport const AUDIO_OUTPUT_NOISE_GATE = 0.03;\nexport const AUDIO_INPUT_NOISE_GATE = 0.045;\n\n/**\n * Soft-knee noise gate: at/below `gate` → 0; above it the remaining range rescales to\n * 0..1 (so the gate never visibly \"clips\" the bottom off real speech). Pure.\n */\nexport function GateLevel(level: number, gate: number): number {\n if (!Number.isFinite(level) || level <= gate) {\n return 0;\n }\n return Math.min(1, (level - gate) / (1 - gate));\n}\n\n/**\n * One smoothing step: fast attack (speech onset reads instantly), slow decay (the level\n * rings down like a speaker cone instead of snapping). Pure.\n */\nexport function SmoothLevel(previous: number, next: number, attack: number = 0.5, decay: number = 0.12): number {\n const factor = next > previous ? attack : decay;\n const value = previous + (next - previous) * factor;\n return Math.min(1, Math.max(0, value));\n}\n\n/**\n * Per-overlay smoothing state machine. Feed it one raw {@link RealtimeAudioActivity}\n * sample per animation frame via {@link Next}; render the returned frame. `null` in →\n * `null` out (the driver attached no meters — the host keeps turn-state visuals).\n */\nexport class RealtimeAudioVisualSmoother {\n private outputLevel = 0;\n private inputLevel = 0;\n private bins: number[] = new Array<number>(AUDIO_VISUAL_BIN_COUNT).fill(0);\n private direction: RealtimeDirection = 'none';\n /** Last time (ms) the current direction's level was at/above the presence floor. */\n private directionHeldAt = 0;\n\n /** Resets all smoothing state (call between sessions). */\n public Reset(): void {\n this.outputLevel = 0;\n this.inputLevel = 0;\n this.bins = new Array<number>(AUDIO_VISUAL_BIN_COUNT).fill(0);\n this.direction = 'none';\n this.directionHeldAt = 0;\n }\n\n /**\n * Advances the smoother with one raw sample.\n * @param raw The client's current audio activity (`null` = no metering capability).\n * @param nowMs A monotonic clock reading (e.g. `performance.now()`).\n * @returns The render-ready frame, or `null` when un-metered.\n */\n public Next(raw: RealtimeAudioActivity | null, nowMs: number): RealtimeAudioVisualFrame | null {\n if (!raw) {\n return null;\n }\n // Gate BEFORE smoothing: silence is true zero, the decay still rings down smoothly.\n const gatedOut = GateLevel(raw.OutputLevel ?? 0, AUDIO_OUTPUT_NOISE_GATE);\n const gatedIn = GateLevel(raw.InputLevel ?? 0, AUDIO_INPUT_NOISE_GATE);\n this.outputLevel = SmoothLevel(this.outputLevel, gatedOut);\n this.inputLevel = SmoothLevel(this.inputLevel, gatedIn);\n this.smoothBins(this.pickRawBins(raw, gatedOut, gatedIn));\n this.resolveDirection(nowMs);\n return {\n OutputLevel: this.outputLevel,\n InputLevel: this.inputLevel,\n Bins: [...this.bins],\n Direction: this.direction\n };\n }\n\n /**\n * The spectrum follows whichever direction is louder (falling back to whichever\n * exists) — but a side whose GATED level is silence contributes no spectrum at all:\n * an idle mic's room-noise bins must not keep the EQ dancing.\n */\n private pickRawBins(raw: RealtimeAudioActivity, gatedOut: number, gatedIn: number): number[] | null {\n const outBins = gatedOut > 0 ? raw.OutputBins : null;\n const inBins = gatedIn > 0 ? raw.InputBins : null;\n if (outBins && inBins) {\n return this.outputLevel >= this.inputLevel ? outBins : inBins;\n }\n return outBins ?? inBins;\n }\n\n private smoothBins(rawBins: number[] | null): void {\n if (!rawBins) {\n // No spectrum available — decay the bars toward silence.\n this.bins = this.bins.map(b => SmoothLevel(b, 0));\n return;\n }\n this.bins = this.bins.map((prev, i) => SmoothLevel(prev, rawBins[i] ?? 0));\n }\n\n /**\n * Direction rules (hysteresis):\n * - silence adopts nothing; speech from silence adopts the louder side immediately;\n * - a live direction RENEWS its hold while at/above the presence floor;\n * - the other side steals the direction only by dominating ({@link AUDIO_DIRECTION_STEAL_FACTOR});\n * - a direction releases to `none` only after {@link AUDIO_DIRECTION_HOLD_MS} of silence —\n * syllable gaps never flicker the color.\n */\n private resolveDirection(nowMs: number): void {\n const out = this.outputLevel;\n const inp = this.inputLevel;\n const audible = out >= AUDIO_PRESENCE_FLOOR || inp >= AUDIO_PRESENCE_FLOOR;\n const louder: RealtimeDirection = out >= inp ? 'agent' : 'user';\n\n if (this.direction === 'none') {\n if (audible) {\n this.direction = louder;\n this.directionHeldAt = nowMs;\n }\n return;\n }\n\n const currentLevel = this.direction === 'agent' ? out : inp;\n const otherLevel = this.direction === 'agent' ? inp : out;\n if (currentLevel >= AUDIO_PRESENCE_FLOOR) {\n this.directionHeldAt = nowMs;\n }\n if (otherLevel >= AUDIO_PRESENCE_FLOOR && otherLevel >= currentLevel * AUDIO_DIRECTION_STEAL_FACTOR) {\n this.direction = this.direction === 'agent' ? 'user' : 'agent';\n this.directionHeldAt = nowMs;\n return;\n }\n if (!audible && nowMs - this.directionHeldAt > AUDIO_DIRECTION_HOLD_MS) {\n this.direction = 'none';\n }\n }\n}\n"]}
|
|
@@ -8,8 +8,9 @@ import * as i0 from "@angular/core";
|
|
|
8
8
|
* - **Levels 0–1 (phone-call strip)** — big round call controls, centered: Mute, the
|
|
9
9
|
* Captions toggle (level 1+, arriving WITH the text it controls), the Details peek
|
|
10
10
|
* (level 0 paths where the surface panel isn't earned yet — lets the user look at the
|
|
11
|
-
* Activity/Whiteboard panels on demand), and End call.
|
|
12
|
-
*
|
|
11
|
+
* Activity/Whiteboard panels on demand), the Type control, and End call. There's no visible
|
|
12
|
+
* composer yet — the Type control opens it, and so does simply starting to type (the overlay
|
|
13
|
+
* captures the first printable keystroke and seeds it via {@link AppendAndFocus}).
|
|
13
14
|
* - **Level 2+ (the dock)** — mute/captions shrink to compact minis and the in-call text
|
|
14
15
|
* input docks beside them (one bottom bar, per Redesign A's fused composer+controls).
|
|
15
16
|
* Submit calls {@link RealtimeSessionService.SendText}, which injects the text as a user
|
|
@@ -25,6 +26,14 @@ export declare class RealtimeComposerComponent {
|
|
|
25
26
|
* never becomes permanent chrome. Default closed (voice-first), reset per session.
|
|
26
27
|
*/
|
|
27
28
|
Open: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* COMPACT (Calm Orb · overlay) presentation: collapse the phone-call strip to the
|
|
31
|
+
* mockup's lean dock — **Mute + End + a "•••"** overflow button. The "•••" blooms a small
|
|
32
|
+
* sheet hosting the secondary actions (Captions / Details / Type). The fused level-2 dock
|
|
33
|
+
* (minis + text input) is unchanged. Fed from the overlay's resolved `Ui.compact`.
|
|
34
|
+
* Default `false` (the full 5-button strip is unchanged).
|
|
35
|
+
*/
|
|
36
|
+
Compact: boolean;
|
|
28
37
|
/** Emitted when the user opens (Type control / typing) or closes (hide control) the dock. */
|
|
29
38
|
OpenChanged: EventEmitter<boolean>;
|
|
30
39
|
/** Whether captions are currently shown (drives the captions control's active state). */
|
|
@@ -39,27 +48,52 @@ export declare class RealtimeComposerComponent {
|
|
|
39
48
|
DetailsToggled: EventEmitter<void>;
|
|
40
49
|
/** Emitted when the user ends the call from the strip's End control. */
|
|
41
50
|
EndRequested: EventEmitter<void>;
|
|
51
|
+
/** Emitted with the new muted state whenever the user toggles the mic from the dock. */
|
|
52
|
+
MuteChanged: EventEmitter<boolean>;
|
|
42
53
|
/** Current draft text in the dock's composer input. */
|
|
43
54
|
Draft: string;
|
|
44
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* The mic mute state. A two-way reflection: the overlay may push it down (e.g. its
|
|
57
|
+
* `SetMuted()` / focus-pill toggle) so all mute affordances stay in sync, and this
|
|
58
|
+
* component updates it locally + emits {@link MuteChanged} when its own button is used.
|
|
59
|
+
*/
|
|
45
60
|
IsMuted: boolean;
|
|
46
61
|
private dockInput?;
|
|
47
|
-
private
|
|
62
|
+
private realtime;
|
|
48
63
|
/** True when there's non-whitespace text to send. */
|
|
49
64
|
get CanSend(): boolean;
|
|
50
65
|
/** True while the big-controls phone-call strip renders (instead of the dock). */
|
|
51
66
|
get StripMode(): boolean;
|
|
52
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* Whether the compact "•••" overflow sheet (Captions / Details / Type) is open. Only used
|
|
69
|
+
* in {@link Compact} strip mode; any outside click or action selection closes it.
|
|
70
|
+
*/
|
|
71
|
+
MoreOpen: boolean;
|
|
72
|
+
/** Open/close the compact overflow sheet (stops propagation so the outside-click close skips it). */
|
|
73
|
+
ToggleMore(event: MouseEvent): void;
|
|
74
|
+
/** Any outside click closes the compact overflow sheet. */
|
|
75
|
+
OnDocumentClick(): void;
|
|
76
|
+
/** Toggle the local microphone mute and surface the new state to the overlay. */
|
|
53
77
|
ToggleMute(): void;
|
|
54
78
|
/** Toggle captions visibility and notify the overlay. */
|
|
55
79
|
ToggleCaptions(): void;
|
|
56
|
-
/** Focuses the dock's text input (the overlay's
|
|
80
|
+
/** Focuses the dock's text input (the overlay's Type control lands here). */
|
|
57
81
|
FocusInput(): void;
|
|
82
|
+
/**
|
|
83
|
+
* TYPE-TO-COMPOSE: the overlay captured a printable keystroke while nothing was focused, so seed
|
|
84
|
+
* the draft with that character, focus the input, and put the caret at the end — the user just
|
|
85
|
+
* keeps typing and their first key isn't lost. Appends (rather than replaces) so a leftover draft
|
|
86
|
+
* is preserved. The native value is synced inline so the caret math is correct before Angular's
|
|
87
|
+
* next change-detection pass reconciles ngModel.
|
|
88
|
+
*
|
|
89
|
+
* @param text the character(s) to seed (typically the single key that opened the composer).
|
|
90
|
+
*/
|
|
91
|
+
AppendAndFocus(text: string): void;
|
|
58
92
|
/** Send the typed text into the live session, then clear the input. */
|
|
59
93
|
Send(): void;
|
|
60
94
|
/** Enter sends (Shift+Enter is free for future multiline if the input becomes a textarea). */
|
|
61
95
|
OnKeydown(event: KeyboardEvent): void;
|
|
62
96
|
static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeComposerComponent, never>;
|
|
63
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeComposerComponent, "mj-realtime-composer", never, { "Open": { "alias": "Open"; "required": false; }; "CaptionsOn": { "alias": "CaptionsOn"; "required": false; }; "ShowDetails": { "alias": "ShowDetails"; "required": false; }; "DetailsOn": { "alias": "DetailsOn"; "required": false; }; }, { "OpenChanged": "OpenChanged"; "CaptionsToggled": "CaptionsToggled"; "DetailsToggled": "DetailsToggled"; "EndRequested": "EndRequested"; }, never, never, true, never>;
|
|
97
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeComposerComponent, "mj-realtime-composer", never, { "Open": { "alias": "Open"; "required": false; }; "Compact": { "alias": "Compact"; "required": false; }; "CaptionsOn": { "alias": "CaptionsOn"; "required": false; }; "ShowDetails": { "alias": "ShowDetails"; "required": false; }; "DetailsOn": { "alias": "DetailsOn"; "required": false; }; "IsMuted": { "alias": "IsMuted"; "required": false; }; }, { "OpenChanged": "OpenChanged"; "CaptionsToggled": "CaptionsToggled"; "DetailsToggled": "DetailsToggled"; "EndRequested": "EndRequested"; "MuteChanged": "MuteChanged"; }, never, never, true, never>;
|
|
64
98
|
}
|
|
65
99
|
//# sourceMappingURL=realtime-composer.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-composer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-composer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,YAAY,
|
|
1
|
+
{"version":3,"file":"realtime-composer.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/realtime/realtime-composer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,YAAY,EAAkD,MAAM,eAAe,CAAC;;AAKpH;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAOa,yBAAyB;IACpC;;;;OAIG;IACM,IAAI,UAAS;IAEtB;;;;;;OAMG;IACM,OAAO,UAAS;IAEzB,6FAA6F;IACnF,WAAW,wBAA+B;IAEpD,yFAAyF;IAChF,UAAU,UAAQ;IAE3B,yFAAyF;IAChF,WAAW,UAAS;IAE7B,gFAAgF;IACvE,SAAS,UAAS;IAE3B,mFAAmF;IACzE,eAAe,wBAA+B;IAExD,oFAAoF;IAC1E,cAAc,qBAA4B;IAEpD,wEAAwE;IAC9D,YAAY,qBAA4B;IAElD,wFAAwF;IAC9E,WAAW,wBAA+B;IAEpD,uDAAuD;IAChD,KAAK,SAAM;IAElB;;;;OAIG;IACM,OAAO,UAAS;IAED,OAAO,CAAC,SAAS,CAAC,CAA+B;IAEzE,OAAO,CAAC,QAAQ,CAAkC;IAElD,qDAAqD;IACrD,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED,kFAAkF;IAClF,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED;;;OAGG;IACI,QAAQ,UAAS;IAExB,qGAAqG;IAC9F,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAK1C,2DAA2D;IAEpD,eAAe,IAAI,IAAI;IAM9B,iFAAiF;IAC1E,UAAU,IAAI,IAAI;IAKzB,yDAAyD;IAClD,cAAc,IAAI,IAAI;IAK7B,6EAA6E;IACtE,UAAU,IAAI,IAAI;IAIzB;;;;;;;;OAQG;IACI,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAUzC,uEAAuE;IAChE,IAAI,IAAI,IAAI;IAQnB,8FAA8F;IACvF,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;yCAnIjC,yBAAyB;2CAAzB,yBAAyB;CAyIrC"}
|