@memberjunction/ng-conversations 6.2.0-edge.2 → 6.2.0-edge.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -7
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-view.component.js +1 -0
- package/dist/lib/components/collection/collection-view.component.js.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.d.ts +14 -2
- package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.js +35 -4
- package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +632 -55
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +2748 -624
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/forks-popover.component.d.ts +37 -0
- package/dist/lib/components/conversation/forks-popover.component.d.ts.map +1 -0
- package/dist/lib/components/conversation/forks-popover.component.js +164 -0
- package/dist/lib/components/conversation/forks-popover.component.js.map +1 -0
- package/dist/lib/components/export/export-modal.component.d.ts +7 -2
- package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
- package/dist/lib/components/export/export-modal.component.js +16 -3
- package/dist/lib/components/export/export-modal.component.js.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.js +11 -9
- package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +121 -11
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +307 -106
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +178 -5
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +919 -306
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +92 -21
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +337 -52
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts +34 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js +75 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts +80 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js +202 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts +45 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js +123 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts +90 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.js +223 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts +98 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.js +161 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts +48 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js +205 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts +19 -2
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/client-context-channel.js +83 -9
- package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +30 -9
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +78 -14
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts +71 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js +259 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts +129 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.js +373 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.js.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts +77 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js +420 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.d.ts +83 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.js +292 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts +39 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.js +152 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts +109 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.js +146 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts +19 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.js +39 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts +183 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js +761 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts +25 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.js +57 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts +40 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js +97 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts +144 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.js +57 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts +36 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.js +55 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts +55 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js +210 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts +32 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js +90 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts +7 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/media/media-channel.js +28 -1
- package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +8 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.js +89 -71
- package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts +21 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.js +49 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +44 -11
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.js +162 -50
- package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +8 -2
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.js +14 -18
- package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.d.ts +42 -2
- package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.js +137 -102
- package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts +71 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.js +221 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +264 -22
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +851 -135
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts +14 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.js +14 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts +74 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.js +171 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +71 -13
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js +232 -73
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +5 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js +8 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.d.ts +12 -2
- package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.js +5 -1
- package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +10 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +42 -2
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +20 -3
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +44 -10
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +28 -44
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +76 -162
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
- 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 +25 -12
- package/dist/lib/components/search/search-panel.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +22 -31
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +50 -63
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/conversations.module.d.ts +30 -29
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +27 -5
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/events/chat-events.d.ts +25 -0
- package/dist/lib/events/chat-events.d.ts.map +1 -1
- package/dist/lib/events/chat-events.js +36 -0
- package/dist/lib/events/chat-events.js.map +1 -1
- package/dist/lib/models/agent-turn.model.d.ts +5 -0
- package/dist/lib/models/agent-turn.model.d.ts.map +1 -1
- package/dist/lib/models/agent-turn.model.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts +34 -8
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +82 -29
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/artifact-state.service.d.ts +0 -9
- package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-state.service.js +1 -32
- package/dist/lib/services/artifact-state.service.js.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.d.ts +12 -0
- package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.js +19 -0
- package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
- package/dist/lib/services/browser-recording-unload-guard.d.ts +30 -0
- package/dist/lib/services/browser-recording-unload-guard.d.ts.map +1 -0
- package/dist/lib/services/browser-recording-unload-guard.js +43 -0
- package/dist/lib/services/browser-recording-unload-guard.js.map +1 -0
- package/dist/lib/services/conversation-agent.service.d.ts +35 -11
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +65 -20
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.d.ts +22 -4
- package/dist/lib/services/conversation-detail-window.store.d.ts.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.js +50 -9
- package/dist/lib/services/conversation-detail-window.store.js.map +1 -1
- package/dist/lib/services/conversation-naming.d.ts +72 -22
- package/dist/lib/services/conversation-naming.d.ts.map +1 -1
- package/dist/lib/services/conversation-naming.js +84 -10
- package/dist/lib/services/conversation-naming.js.map +1 -1
- package/dist/lib/services/data-cache.service.d.ts +13 -5
- package/dist/lib/services/data-cache.service.d.ts.map +1 -1
- package/dist/lib/services/data-cache.service.js +39 -19
- package/dist/lib/services/data-cache.service.js.map +1 -1
- package/dist/lib/services/export.service.d.ts +26 -9
- package/dist/lib/services/export.service.d.ts.map +1 -1
- package/dist/lib/services/export.service.js +61 -18
- package/dist/lib/services/export.service.js.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.d.ts +33 -5
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.js +71 -11
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
- package/dist/lib/services/realtime-pairing.d.ts +10 -5
- package/dist/lib/services/realtime-pairing.d.ts.map +1 -1
- package/dist/lib/services/realtime-pairing.js +15 -6
- package/dist/lib/services/realtime-pairing.js.map +1 -1
- package/dist/lib/services/realtime-session.service.d.ts +3 -2
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +7 -2
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/search.service.d.ts +7 -2
- package/dist/lib/services/search.service.d.ts.map +1 -1
- package/dist/lib/services/search.service.js +13 -4
- package/dist/lib/services/search.service.js.map +1 -1
- package/dist/lib/util/frame-zone.d.ts +10 -0
- package/dist/lib/util/frame-zone.d.ts.map +1 -0
- package/dist/lib/util/frame-zone.js +10 -0
- package/dist/lib/util/frame-zone.js.map +1 -0
- package/dist/lib/utils/conversation-branching.d.ts +4 -0
- package/dist/lib/utils/conversation-branching.d.ts.map +1 -0
- package/dist/lib/utils/conversation-branching.js +5 -0
- package/dist/lib/utils/conversation-branching.js.map +1 -0
- package/dist/lib/utils/conversation-forks.d.ts +315 -0
- package/dist/lib/utils/conversation-forks.d.ts.map +1 -0
- package/dist/lib/utils/conversation-forks.js +456 -0
- package/dist/lib/utils/conversation-forks.js.map +1 -0
- package/dist/public-api.d.ts +23 -1
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +30 -1
- package/dist/public-api.js.map +1 -1
- package/package.json +37 -32
- package/dist/lib/components/thread/thread-panel.component.d.ts +0 -126
- package/dist/lib/components/thread/thread-panel.component.d.ts.map +0 -1
- package/dist/lib/components/thread/thread-panel.component.js +0 -440
- package/dist/lib/components/thread/thread-panel.component.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-camera-check-card.component.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/capture/realtime-camera-check-card.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC3H,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;;AAIzE;;;;;;;;GAQG;AA0BH,MAAM,OAAO,gCAAgC;IAC1B,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACzC,MAAM,GAAgC,IAAI,CAAC;IAC3C,MAAM,GAA4B,IAAI,CAAC;IAC/C,2DAA2D;IACnD,WAAW,GAAkB,IAAI,CAAC;IAE1C,mDAAmD;IACnC,SAAS,GAAG,eAAe,CAAC;IAE5C,uGAAuG;IACvF,MAAM,GAAoD,IAAI,CAAC;IAE/E,8FAA8F;IAC9F,IACW,MAAM,CAAC,KAAkC;QAClD,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,IAAI,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9D,CAAC;IACD,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,mDAAmD;IAClC,SAAS,GAAG,IAAI,YAAY,EAAQ,CAAC;IACtD,6BAA6B;IACZ,QAAQ,GAAG,IAAI,YAAY,EAAQ,CAAC;IAErD,sFAAsF;IACtF,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,kCAAkC;IAClC,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC;IACpC,CAAC;IAED,2EAA2E;IAC3E,IAAW,gBAAgB;QACzB,OAAO,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,EAAE,QAAQ,IAAI,IAAI,CAAC;IAC3D,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,gBAAgB,CAAC,SAA+B;QAC3D,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,IAAI,SAAS,CAAC,QAAQ,KAAK,IAAI,CAAC,MAAM,EAAE,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAChG,OAAO;QACT,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC,QAAQ,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;0HA3DU,gCAAgC;6DAAhC,gCAAgC;YAnBzC,oCAA4F;YAA1B,gHAAS,mBAAe,IAAC;YACzF,4BAA8B;YAAA,YAAqD;YAAA,iBAAI;YACvF,0CAYC;YADC,AADA,AADA,8HAAa,oBAAgB,IAAC,iHACjB,mBAAe,IAAC,iIACX,4BAAwB,IAAC;YAE/C,AADG,iBAAkB,EACT;;YAfD,8BAAgB;YACK,eAAqD;YAArD,kFAAqD;YAKjF,cAAsB;YAItB,AADA,AADA,AADA,AADA,oCAAsB,kBACL,4BACM,wBACJ,0CACkB;4BAbjC,iBAAiB,EAAE,oBAAoB;;iFAsBtC,gCAAgC;cAzB5C,SAAS;6BACI,IAAI,YACN,+BAA+B,WAChC,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,mBACjC,uBAAuB,CAAC,MAAM,YACrC;;;;;;;;;;;;;;;;;GAiBT;;kBAWA,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAUL,MAAM;;kBAEN,MAAM;;kFA1BI,gCAAgC;AA8D7C,mHAAmH;AACnH,SAAS,SAAS,CAAC,MAA0B,EAAE,QAAiC;IAC9E,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,QAAQ,EAAE,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACnH,CAAC","sourcesContent":["import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, inject } from '@angular/core';\nimport { MJDialogComponent } from '@memberjunction/ng-ui-components';\nimport { CameraCheckComponent } from '@memberjunction/ng-realtime-media';\nimport type { MediaDevice, MediaDeviceSelection, MediaVideoSource } from '@memberjunction/ai-realtime-client/media';\nimport type { RealtimeCaptureState } from '@memberjunction/realtime-runtime';\n\n/**\n * `mj-realtime-camera-check-card`: the camera check over the call. The first time the user turns the camera on in a call,\n * the camera opens for them alone ({@link RealtimeCaptureState.Checking}) and this card shows it, mirrored, with the\n * cameras to choose from. It checks the camera only: it gives `mj-camera-check` no microphones, no level and no buttons. \"Turn on camera\" lets the agent see it ({@link Confirmed}); \"Not now\", the close button,\n * Escape and a click outside turn it off ({@link Declined}).\n *\n * Presentational: the overlay gives it the camera's state and a way to {@link Switch} cameras, and calls the session for\n * each answer.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-camera-check-card',\n imports: [MJDialogComponent, CameraCheckComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <mj-dialog [Visible]=\"true\" Title=\"Check your camera\" Size=\"auto\" (Close)=\"Declined.emit()\">\n <p class=\"camera-check__note\">{{ AgentName }} sees your camera once you turn it on.</p>\n <mj-camera-check\n Heading=\"\"\n ConfirmLabel=\"Turn on camera\"\n CancelLabel=\"Not now\"\n [ShowControls]=\"false\"\n [CameraOn]=\"true\"\n [CameraSource]=\"Source\"\n [Devices]=\"Devices\"\n [SelectedCameraID]=\"SelectedCameraID\"\n (Confirmed)=\"Confirmed.emit()\"\n (Cancelled)=\"Declined.emit()\"\n (DeviceSelected)=\"OnDeviceSelected($event)\"\n ></mj-camera-check>\n </mj-dialog>\n `,\n styleUrls: ['./realtime-camera-check-card.component.css'],\n})\nexport class RealtimeCameraCheckCardComponent {\n private readonly cdr = inject(ChangeDetectorRef);\n private camera: RealtimeCaptureState | null = null;\n private source: MediaVideoSource | null = null;\n /** The camera being switched to, while the switch runs. */\n private switchingTo: string | null = null;\n\n /** Who the user is about to show the camera to. */\n @Input() public AgentName = 'The assistant';\n\n /** Moves the camera to another device and resolves once it has, or has gone back to the one in use. */\n @Input() public Switch: ((deviceId: string) => Promise<unknown>) | null = null;\n\n /** The camera being checked: its stream, the camera in use and the cameras to choose from. */\n @Input()\n public set Camera(value: RealtimeCaptureState | null) {\n this.camera = value;\n this.source = sourceFor(value?.Stream ?? null, this.source);\n }\n public get Camera(): RealtimeCaptureState | null {\n return this.camera;\n }\n\n /** The user turned the camera on for the agent. */\n @Output() public Confirmed = new EventEmitter<void>();\n /** The user said not now. */\n @Output() public Declined = new EventEmitter<void>();\n\n /** The preview: the camera's stream, the same object while the stream is the same. */\n public get Source(): MediaVideoSource | null {\n return this.source;\n }\n\n /** The cameras to choose from. */\n public get Devices(): readonly MediaDevice[] {\n return this.camera?.Devices ?? [];\n }\n\n /** The picker's camera: the one being switched to, else the one in use. */\n public get SelectedCameraID(): string | null {\n return this.switchingTo ?? this.camera?.DeviceID ?? null;\n }\n\n /**\n * A camera picked in the check. The picker shows it while the camera switches, then the camera in use: the new one, or\n * the old one when the new one could not open. A pick of the camera in use changes nothing.\n */\n public async OnDeviceSelected(selection: MediaDeviceSelection): Promise<void> {\n if (selection.Kind !== 'camera' || selection.DeviceID === this.camera?.DeviceID || !this.Switch) {\n return;\n }\n this.switchingTo = selection.DeviceID;\n this.cdr.markForCheck();\n try {\n await this.Switch(selection.DeviceID);\n } finally {\n this.switchingTo = null;\n this.cdr.markForCheck();\n }\n }\n}\n\n/** The preview for a stream: the previous one while the stream is the same, so the check keeps its video bound. */\nfunction sourceFor(stream: MediaStream | null, previous: MediaVideoSource | null): MediaVideoSource | null {\n if (!stream) {\n return null;\n }\n return previous?.Kind === 'stream' && previous.Stream === stream ? previous : { Kind: 'stream', Stream: stream };\n}\n"]}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Type } from '@angular/core';
|
|
2
|
+
import type { JSONObject } from '@memberjunction/ai';
|
|
3
|
+
import { type RealtimeChannelDescriptor } from '@memberjunction/ai-core-plus';
|
|
4
|
+
import { BaseRealtimeChannelClient, type ChannelExposureSettings, type RealtimeCaptureKind, type RealtimeChannelVerbResult, type RealtimeHostChannelDeclaration, type RealtimeSessionStartOptions } from '@memberjunction/realtime-runtime';
|
|
5
|
+
import { RealtimeCaptureModel } from './realtime-capture-model';
|
|
6
|
+
import { RealtimeCaptureSurfaceComponent } from './realtime-capture-surface.component';
|
|
7
|
+
/** The registry keys (`MJ: AI Agent Channels` → `Name` and `ClientPluginClass`) of the two capture channels. */
|
|
8
|
+
export declare const REALTIME_CAMERA_CHANNEL_NAME = "Camera";
|
|
9
|
+
export declare const REALTIME_SCREEN_SHARE_CHANNEL_NAME = "ScreenShare";
|
|
10
|
+
export declare const REALTIME_CAMERA_CHANNEL_CLASS = "RealtimeCameraChannel";
|
|
11
|
+
export declare const REALTIME_SCREEN_SHARE_CHANNEL_CLASS = "RealtimeScreenShareChannel";
|
|
12
|
+
/**
|
|
13
|
+
* The channels the conversations UI brings to its calls: the Camera and Screen Share channels are opt-in, so a call has
|
|
14
|
+
* them only when its host (or the agent's or app's configuration) asks. An agent or app can still exclude them.
|
|
15
|
+
*/
|
|
16
|
+
export declare const CONVERSATION_CALL_HOST_CHANNELS: readonly RealtimeHostChannelDeclaration[];
|
|
17
|
+
/**
|
|
18
|
+
* The start options the conversations UI passes with every call it starts: the channels it brings, and the camera check
|
|
19
|
+
* its call overlay shows the first time the user turns the camera on in a call.
|
|
20
|
+
*/
|
|
21
|
+
export declare function ConversationCallStartOptions(): RealtimeSessionStartOptions;
|
|
22
|
+
/** What tells the two capture channels apart. */
|
|
23
|
+
interface CaptureChannelText {
|
|
24
|
+
Kind: RealtimeCaptureKind;
|
|
25
|
+
Key: string;
|
|
26
|
+
DisplayName: string;
|
|
27
|
+
TabIcon: string;
|
|
28
|
+
Instructions: string;
|
|
29
|
+
Status: string;
|
|
30
|
+
ReasonHint: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A channel that fronts one of the runtime's captures: the user's camera or a shared screen. It is the agent's contract
|
|
34
|
+
* for asking to see it, and the capture's policy (`CaptureKind`): the runtime starts the capture only while this channel
|
|
35
|
+
* is in the call and may show the agent pixels.
|
|
36
|
+
*
|
|
37
|
+
* **The agent only asks.** Opening the channel, with a `reason`, is the request: the channel's surface appears where its
|
|
38
|
+
* registry row places it (picture-in-picture) and shows the ask, with the user's choice of turning it on or "Not now".
|
|
39
|
+
* Only the user starts or stops the capture; the agent learns what happened from the channel's `status`.
|
|
40
|
+
*
|
|
41
|
+
* Both channels are `on-demand` (listed in the agent's catalog, mounted when opened), `opt-in` (a call has them only when
|
|
42
|
+
* its host or configuration asks for them; the conversations UI brings them, see {@link CONVERSATION_CALL_HOST_CHANNELS})
|
|
43
|
+
* and may show the agent pixels. Their server half is the generic `ClientOnlyChannelServer`.
|
|
44
|
+
*/
|
|
45
|
+
export declare abstract class RealtimeCaptureChannel extends BaseRealtimeChannelClient<RealtimeCaptureSurfaceComponent> {
|
|
46
|
+
private model;
|
|
47
|
+
private capturesSub;
|
|
48
|
+
private sourcesSub;
|
|
49
|
+
private surfaceSubs;
|
|
50
|
+
/** What makes this channel the camera or the screen share. */
|
|
51
|
+
protected abstract get Text(): CaptureChannelText;
|
|
52
|
+
/** The channel's state. Public so the surface and tests share the one instance. */
|
|
53
|
+
get Model(): RealtimeCaptureModel;
|
|
54
|
+
/** The capture this channel fronts. */
|
|
55
|
+
get CaptureKind(): RealtimeCaptureKind;
|
|
56
|
+
get ChannelName(): string;
|
|
57
|
+
get TabTitle(): string;
|
|
58
|
+
get TabIcon(): string;
|
|
59
|
+
GetDescriptor(): RealtimeChannelDescriptor;
|
|
60
|
+
GetState(): JSONObject;
|
|
61
|
+
GetSurfaceComponent(): Type<RealtimeCaptureSurfaceComponent>;
|
|
62
|
+
protected OnInitialize(): void;
|
|
63
|
+
/** The agent's request: opening the channel, again or for the first time, asks the user. */
|
|
64
|
+
protected OnOpen(inputs: JSONObject): RealtimeChannelVerbResult;
|
|
65
|
+
ApplyExposure(settings: ChannelExposureSettings): void;
|
|
66
|
+
BindSurface(instance: RealtimeCaptureSurfaceComponent): void;
|
|
67
|
+
UnbindSurface(): void;
|
|
68
|
+
Dispose(): void;
|
|
69
|
+
/** Streams the change's event, and tells the agent (one coalesced note) what changed. */
|
|
70
|
+
private onModelChange;
|
|
71
|
+
/** "Change" on a share: stops it and asks the browser's picker again. */
|
|
72
|
+
private changeShare;
|
|
73
|
+
private unbindSurfaceOutputs;
|
|
74
|
+
private nouns;
|
|
75
|
+
}
|
|
76
|
+
/** The CAMERA channel: the agent asks to see the user's camera; only the user turns it on or off. */
|
|
77
|
+
export declare class RealtimeCameraChannel extends RealtimeCaptureChannel {
|
|
78
|
+
protected get Text(): CaptureChannelText;
|
|
79
|
+
}
|
|
80
|
+
/** The SCREEN SHARE channel: the agent asks to see the user's screen; only the user shares or stops. */
|
|
81
|
+
export declare class RealtimeScreenShareChannel extends RealtimeCaptureChannel {
|
|
82
|
+
protected get Text(): CaptureChannelText;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Tree-shaking prevention: the channels are resolved through the ClassFactory by their registry rows' `ClientPluginClass`
|
|
86
|
+
* keys, so this static call keeps their `@RegisterClass` side effects alive.
|
|
87
|
+
*/
|
|
88
|
+
export declare function LoadRealtimeCaptureChannels(): void;
|
|
89
|
+
export {};
|
|
90
|
+
//# sourceMappingURL=realtime-capture-channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-capture-channel.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/capture/realtime-capture-channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAG1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAqC,KAAK,yBAAyB,EAA4B,MAAM,8BAA8B,CAAC;AAC3I,OAAO,EACL,yBAAyB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EACjC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAA8B,MAAM,0BAA0B,CAAC;AAC5F,OAAO,EAAE,+BAA+B,EAAE,MAAM,sCAAsC,CAAC;AAEvF,gHAAgH;AAChH,eAAO,MAAM,4BAA4B,WAAW,CAAC;AACrD,eAAO,MAAM,kCAAkC,gBAAgB,CAAC;AAChE,eAAO,MAAM,6BAA6B,0BAA0B,CAAC;AACrE,eAAO,MAAM,mCAAmC,+BAA+B,CAAC;AAEhF;;;GAGG;AACH,eAAO,MAAM,+BAA+B,EAAE,SAAS,8BAA8B,EAGnF,CAAC;AAEH;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,2BAA2B,CAE1E;AAED,iDAAiD;AACjD,UAAU,kBAAkB;IAC1B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;;;;;;;;;;;GAYG;AACH,8BAAsB,sBAAuB,SAAQ,yBAAyB,CAAC,+BAA+B,CAAC;IAC7G,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,WAAW,CAAsB;IAEzC,8DAA8D;IAC9D,SAAS,CAAC,QAAQ,KAAK,IAAI,IAAI,kBAAkB,CAAC;IAElD,mFAAmF;IACnF,IAAW,KAAK,IAAI,oBAAoB,CAGvC;IAED,uCAAuC;IACvC,IAAoB,WAAW,IAAI,mBAAmB,CAErD;IAED,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,IAAoB,QAAQ,IAAI,MAAM,CAErC;IAED,IAAoB,OAAO,IAAI,MAAM,CAEpC;IAEe,aAAa,IAAI,yBAAyB;IA4B1C,QAAQ,IAAI,UAAU;IAItB,mBAAmB,IAAI,IAAI,CAAC,+BAA+B,CAAC;cAIzD,YAAY,IAAI,IAAI;IASvC,4FAA4F;cACzE,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,yBAAyB;IAMxD,aAAa,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAKtD,WAAW,CAAC,QAAQ,EAAE,+BAA+B,GAAG,IAAI;IAY5D,aAAa,IAAI,IAAI;IAIrB,OAAO,IAAI,IAAI;IAU/B,yFAAyF;IACzF,OAAO,CAAC,aAAa;IAOrB,yEAAyE;IACzE,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,KAAK;CAed;AAED,qGAAqG;AACrG,qBACa,qBAAsB,SAAQ,sBAAsB;IAC/D,cAAuB,IAAI,IAAI,kBAAkB,CAahD;CACF;AAED,wGAAwG;AACxG,qBACa,0BAA2B,SAAQ,sBAAsB;IACpE,cAAuB,IAAI,IAAI,kBAAkB,CAchD;CACF;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
8
|
+
import { REALTIME_CHANNEL_CONTRACT_VERSION } from '@memberjunction/ai-core-plus';
|
|
9
|
+
import { BaseRealtimeChannelClient, } from '@memberjunction/realtime-runtime';
|
|
10
|
+
import { RealtimeCaptureModel } from './realtime-capture-model';
|
|
11
|
+
import { RealtimeCaptureSurfaceComponent } from './realtime-capture-surface.component';
|
|
12
|
+
/** The registry keys (`MJ: AI Agent Channels` → `Name` and `ClientPluginClass`) of the two capture channels. */
|
|
13
|
+
export const REALTIME_CAMERA_CHANNEL_NAME = 'Camera';
|
|
14
|
+
export const REALTIME_SCREEN_SHARE_CHANNEL_NAME = 'ScreenShare';
|
|
15
|
+
export const REALTIME_CAMERA_CHANNEL_CLASS = 'RealtimeCameraChannel';
|
|
16
|
+
export const REALTIME_SCREEN_SHARE_CHANNEL_CLASS = 'RealtimeScreenShareChannel';
|
|
17
|
+
/**
|
|
18
|
+
* The channels the conversations UI brings to its calls: the Camera and Screen Share channels are opt-in, so a call has
|
|
19
|
+
* them only when its host (or the agent's or app's configuration) asks. An agent or app can still exclude them.
|
|
20
|
+
*/
|
|
21
|
+
export const CONVERSATION_CALL_HOST_CHANNELS = Object.freeze([
|
|
22
|
+
{ ClientPluginClass: REALTIME_CAMERA_CHANNEL_CLASS },
|
|
23
|
+
{ ClientPluginClass: REALTIME_SCREEN_SHARE_CHANNEL_CLASS },
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* The start options the conversations UI passes with every call it starts: the channels it brings, and the camera check
|
|
27
|
+
* its call overlay shows the first time the user turns the camera on in a call.
|
|
28
|
+
*/
|
|
29
|
+
export function ConversationCallStartOptions() {
|
|
30
|
+
return { HostChannels: [...CONVERSATION_CALL_HOST_CHANNELS], CameraCheck: true };
|
|
31
|
+
}
|
|
32
|
+
const STATUS_VALUES = ['off', 'asked', 'starting', 'on', 'failed'];
|
|
33
|
+
/**
|
|
34
|
+
* A channel that fronts one of the runtime's captures: the user's camera or a shared screen. It is the agent's contract
|
|
35
|
+
* for asking to see it, and the capture's policy (`CaptureKind`): the runtime starts the capture only while this channel
|
|
36
|
+
* is in the call and may show the agent pixels.
|
|
37
|
+
*
|
|
38
|
+
* **The agent only asks.** Opening the channel, with a `reason`, is the request: the channel's surface appears where its
|
|
39
|
+
* registry row places it (picture-in-picture) and shows the ask, with the user's choice of turning it on or "Not now".
|
|
40
|
+
* Only the user starts or stops the capture; the agent learns what happened from the channel's `status`.
|
|
41
|
+
*
|
|
42
|
+
* Both channels are `on-demand` (listed in the agent's catalog, mounted when opened), `opt-in` (a call has them only when
|
|
43
|
+
* its host or configuration asks for them; the conversations UI brings them, see {@link CONVERSATION_CALL_HOST_CHANNELS})
|
|
44
|
+
* and may show the agent pixels. Their server half is the generic `ClientOnlyChannelServer`.
|
|
45
|
+
*/
|
|
46
|
+
export class RealtimeCaptureChannel extends BaseRealtimeChannelClient {
|
|
47
|
+
model = null;
|
|
48
|
+
capturesSub = null;
|
|
49
|
+
sourcesSub = null;
|
|
50
|
+
surfaceSubs = [];
|
|
51
|
+
/** The channel's state. Public so the surface and tests share the one instance. */
|
|
52
|
+
get Model() {
|
|
53
|
+
this.model ??= new RealtimeCaptureModel(this.CaptureKind);
|
|
54
|
+
return this.model;
|
|
55
|
+
}
|
|
56
|
+
/** The capture this channel fronts. */
|
|
57
|
+
get CaptureKind() {
|
|
58
|
+
return this.Text.Kind;
|
|
59
|
+
}
|
|
60
|
+
get ChannelName() {
|
|
61
|
+
return this.Text.Key;
|
|
62
|
+
}
|
|
63
|
+
get TabTitle() {
|
|
64
|
+
return this.Text.DisplayName;
|
|
65
|
+
}
|
|
66
|
+
get TabIcon() {
|
|
67
|
+
return this.Text.TabIcon;
|
|
68
|
+
}
|
|
69
|
+
GetDescriptor() {
|
|
70
|
+
const text = this.Text;
|
|
71
|
+
return {
|
|
72
|
+
Key: text.Key,
|
|
73
|
+
Version: REALTIME_CHANNEL_CONTRACT_VERSION,
|
|
74
|
+
DisplayName: text.DisplayName,
|
|
75
|
+
OwningPackage: '@memberjunction/ng-conversations',
|
|
76
|
+
Instructions: text.Instructions,
|
|
77
|
+
Nouns: this.nouns(text),
|
|
78
|
+
Verbs: [],
|
|
79
|
+
Inputs: {
|
|
80
|
+
type: 'object',
|
|
81
|
+
properties: { reason: { type: 'string', maxLength: 200, description: text.ReasonHint } },
|
|
82
|
+
additionalProperties: false,
|
|
83
|
+
},
|
|
84
|
+
Events: [
|
|
85
|
+
{ Name: 'asked', Description: 'Your request is showing to the user.' },
|
|
86
|
+
{ Name: 'declined', Description: 'The user said "Not now" to your request.' },
|
|
87
|
+
{ Name: 'started', Description: 'The user turned it on; you receive it as video.' },
|
|
88
|
+
{ Name: 'stopped', Description: 'The user turned it off.' },
|
|
89
|
+
{ Name: 'failed', Description: 'It could not start; the payload says why.' },
|
|
90
|
+
],
|
|
91
|
+
DisplayPolicy: 'on-demand',
|
|
92
|
+
DefaultAvailability: 'opt-in',
|
|
93
|
+
MaxExposure: 'pixels',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
GetState() {
|
|
97
|
+
return this.Model.ToState();
|
|
98
|
+
}
|
|
99
|
+
GetSurfaceComponent() {
|
|
100
|
+
return RealtimeCaptureSurfaceComponent;
|
|
101
|
+
}
|
|
102
|
+
OnInitialize() {
|
|
103
|
+
this.Model.OnChange((change) => this.onModelChange(change));
|
|
104
|
+
this.Model.SetAgentCanSee(this.Exposure === 'pixels');
|
|
105
|
+
// The sources first, so the model knows whether the capture's frames are sent before it hears the capture is on.
|
|
106
|
+
this.sourcesSub = this.Context?.VideoSources$?.subscribe((sources) => this.Model.FollowVideoSources(sources)) ?? null;
|
|
107
|
+
this.capturesSub =
|
|
108
|
+
this.Context?.Captures$?.subscribe((states) => this.Model.FollowCapture(this.CaptureKind === 'camera' ? states.Camera : states.Screen)) ?? null;
|
|
109
|
+
}
|
|
110
|
+
/** The agent's request: opening the channel, again or for the first time, asks the user. */
|
|
111
|
+
OnOpen(inputs) {
|
|
112
|
+
const reason = typeof inputs['reason'] === 'string' ? inputs['reason'] : null;
|
|
113
|
+
const asked = this.Model.Ask(reason);
|
|
114
|
+
return { Success: true, Result: { asked, status: this.Model.View.Status } };
|
|
115
|
+
}
|
|
116
|
+
ApplyExposure(settings) {
|
|
117
|
+
super.ApplyExposure(settings);
|
|
118
|
+
this.Model.SetAgentCanSee(this.Exposure === 'pixels');
|
|
119
|
+
}
|
|
120
|
+
BindSurface(instance) {
|
|
121
|
+
this.unbindSurfaceOutputs();
|
|
122
|
+
instance.Model = this.Model;
|
|
123
|
+
instance.AgentName = this.Context?.AgentName ?? 'The assistant';
|
|
124
|
+
this.surfaceSubs = [
|
|
125
|
+
instance.StartRequested.subscribe(() => void this.Context?.StartCapture?.(this.CaptureKind)),
|
|
126
|
+
instance.DeclineRequested.subscribe(() => this.Model.Decline()),
|
|
127
|
+
instance.StopRequested.subscribe(() => this.Context?.StopCapture?.(this.CaptureKind)),
|
|
128
|
+
instance.ChangeRequested.subscribe(() => this.changeShare()),
|
|
129
|
+
];
|
|
130
|
+
}
|
|
131
|
+
UnbindSurface() {
|
|
132
|
+
this.unbindSurfaceOutputs();
|
|
133
|
+
}
|
|
134
|
+
Dispose() {
|
|
135
|
+
this.capturesSub?.unsubscribe();
|
|
136
|
+
this.capturesSub = null;
|
|
137
|
+
this.sourcesSub?.unsubscribe();
|
|
138
|
+
this.sourcesSub = null;
|
|
139
|
+
this.unbindSurfaceOutputs();
|
|
140
|
+
this.Model.OnChange(null);
|
|
141
|
+
super.Dispose();
|
|
142
|
+
}
|
|
143
|
+
/** Streams the change's event, and tells the agent (one coalesced note) what changed. */
|
|
144
|
+
onModelChange(change) {
|
|
145
|
+
if (change.Event) {
|
|
146
|
+
this.EmitChannelEvent(change.Event.Name, change.Event.Payload);
|
|
147
|
+
}
|
|
148
|
+
this.RecordChange({ Author: change.Event?.Name === 'asked' ? 'agent' : change.Event ? 'user' : 'system' });
|
|
149
|
+
}
|
|
150
|
+
/** "Change" on a share: stops it and asks the browser's picker again. */
|
|
151
|
+
changeShare() {
|
|
152
|
+
this.Context?.StopCapture?.(this.CaptureKind);
|
|
153
|
+
void this.Context?.StartCapture?.(this.CaptureKind);
|
|
154
|
+
}
|
|
155
|
+
unbindSurfaceOutputs() {
|
|
156
|
+
this.surfaceSubs.forEach((sub) => sub.unsubscribe());
|
|
157
|
+
this.surfaceSubs = [];
|
|
158
|
+
}
|
|
159
|
+
nouns(text) {
|
|
160
|
+
const nouns = [
|
|
161
|
+
{ Name: 'status', Description: text.Status, Schema: { type: 'string', enum: STATUS_VALUES } },
|
|
162
|
+
{ Name: 'reason', Description: 'The reason your standing request shows the user, or empty.', Schema: { type: 'string' } },
|
|
163
|
+
{ Name: 'problem', Description: 'Why it last failed to start, in plain words, or empty.', Schema: { type: 'string' } },
|
|
164
|
+
];
|
|
165
|
+
if (this.CaptureKind === 'screen') {
|
|
166
|
+
nouns.push({
|
|
167
|
+
Name: 'surface',
|
|
168
|
+
Description: 'What the user shares while on: their entire screen, a window or a browser tab ("unknown" when the browser does not say).',
|
|
169
|
+
Schema: { type: 'string', enum: ['screen', 'window', 'tab', 'unknown'] },
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return nouns;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/** The CAMERA channel: the agent asks to see the user's camera; only the user turns it on or off. */
|
|
176
|
+
let RealtimeCameraChannel = class RealtimeCameraChannel extends RealtimeCaptureChannel {
|
|
177
|
+
get Text() {
|
|
178
|
+
return {
|
|
179
|
+
Kind: 'camera',
|
|
180
|
+
Key: REALTIME_CAMERA_CHANNEL_NAME,
|
|
181
|
+
DisplayName: 'Camera',
|
|
182
|
+
TabIcon: 'fa-solid fa-video',
|
|
183
|
+
Instructions: "The user's camera. To see it, open this channel with a short `reason` the user will read (for example, to look at " +
|
|
184
|
+
'something they are holding). That only asks: the user decides, and only they turn the camera on or off, so never say ' +
|
|
185
|
+
'you turned it on. Once it is on you receive it as video. If the user says no, do not ask again unless they bring it up.',
|
|
186
|
+
Status: 'off; asked (your request is showing); starting; on (you receive the camera); failed (see problem).',
|
|
187
|
+
ReasonHint: 'Why you want to see their camera, in a few words they will read.',
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
RealtimeCameraChannel = __decorate([
|
|
192
|
+
RegisterClass(BaseRealtimeChannelClient, REALTIME_CAMERA_CHANNEL_CLASS)
|
|
193
|
+
], RealtimeCameraChannel);
|
|
194
|
+
export { RealtimeCameraChannel };
|
|
195
|
+
/** The SCREEN SHARE channel: the agent asks to see the user's screen; only the user shares or stops. */
|
|
196
|
+
let RealtimeScreenShareChannel = class RealtimeScreenShareChannel extends RealtimeCaptureChannel {
|
|
197
|
+
get Text() {
|
|
198
|
+
return {
|
|
199
|
+
Kind: 'screen',
|
|
200
|
+
Key: REALTIME_SCREEN_SHARE_CHANNEL_NAME,
|
|
201
|
+
DisplayName: 'Screen share',
|
|
202
|
+
TabIcon: 'fa-solid fa-display',
|
|
203
|
+
Instructions: "The user's screen. To see it, open this channel with a short `reason` the user will read (for example, to look at an " +
|
|
204
|
+
'error they mention). That only asks: the user picks a screen, window or tab in their browser and can stop at any ' +
|
|
205
|
+
'time, so never say you started it. Once shared you receive it as video. If the user says no, do not ask again unless ' +
|
|
206
|
+
'they bring it up.',
|
|
207
|
+
Status: 'off; asked (your request is showing); starting (the user is choosing); on (you receive it); failed (see problem).',
|
|
208
|
+
ReasonHint: 'Why you want to see their screen, in a few words they will read.',
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
RealtimeScreenShareChannel = __decorate([
|
|
213
|
+
RegisterClass(BaseRealtimeChannelClient, REALTIME_SCREEN_SHARE_CHANNEL_CLASS)
|
|
214
|
+
], RealtimeScreenShareChannel);
|
|
215
|
+
export { RealtimeScreenShareChannel };
|
|
216
|
+
/**
|
|
217
|
+
* Tree-shaking prevention: the channels are resolved through the ClassFactory by their registry rows' `ClientPluginClass`
|
|
218
|
+
* keys, so this static call keeps their `@RegisterClass` side effects alive.
|
|
219
|
+
*/
|
|
220
|
+
export function LoadRealtimeCaptureChannels() {
|
|
221
|
+
// intentional no-op: the import side effect performs the registration
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=realtime-capture-channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-capture-channel.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/capture/realtime-capture-channel.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Type } from '@angular/core';\nimport type { Subscription } from 'rxjs';\nimport { RegisterClass } from '@memberjunction/global';\nimport type { JSONObject } from '@memberjunction/ai';\nimport { REALTIME_CHANNEL_CONTRACT_VERSION, type RealtimeChannelDescriptor, type RealtimeChannelNoun } from '@memberjunction/ai-core-plus';\nimport {\n BaseRealtimeChannelClient,\n type ChannelExposureSettings,\n type RealtimeCaptureKind,\n type RealtimeChannelVerbResult,\n type RealtimeHostChannelDeclaration,\n type RealtimeSessionStartOptions,\n} from '@memberjunction/realtime-runtime';\nimport { RealtimeCaptureModel, type RealtimeCaptureChange } from './realtime-capture-model';\nimport { RealtimeCaptureSurfaceComponent } from './realtime-capture-surface.component';\n\n/** The registry keys (`MJ: AI Agent Channels` → `Name` and `ClientPluginClass`) of the two capture channels. */\nexport const REALTIME_CAMERA_CHANNEL_NAME = 'Camera';\nexport const REALTIME_SCREEN_SHARE_CHANNEL_NAME = 'ScreenShare';\nexport const REALTIME_CAMERA_CHANNEL_CLASS = 'RealtimeCameraChannel';\nexport const REALTIME_SCREEN_SHARE_CHANNEL_CLASS = 'RealtimeScreenShareChannel';\n\n/**\n * The channels the conversations UI brings to its calls: the Camera and Screen Share channels are opt-in, so a call has\n * them only when its host (or the agent's or app's configuration) asks. An agent or app can still exclude them.\n */\nexport const CONVERSATION_CALL_HOST_CHANNELS: readonly RealtimeHostChannelDeclaration[] = Object.freeze([\n { ClientPluginClass: REALTIME_CAMERA_CHANNEL_CLASS },\n { ClientPluginClass: REALTIME_SCREEN_SHARE_CHANNEL_CLASS },\n]);\n\n/**\n * The start options the conversations UI passes with every call it starts: the channels it brings, and the camera check\n * its call overlay shows the first time the user turns the camera on in a call.\n */\nexport function ConversationCallStartOptions(): RealtimeSessionStartOptions {\n return { HostChannels: [...CONVERSATION_CALL_HOST_CHANNELS], CameraCheck: true };\n}\n\n/** What tells the two capture channels apart. */\ninterface CaptureChannelText {\n Kind: RealtimeCaptureKind;\n Key: string;\n DisplayName: string;\n TabIcon: string;\n Instructions: string;\n Status: string;\n ReasonHint: string;\n}\n\nconst STATUS_VALUES = ['off', 'asked', 'starting', 'on', 'failed'];\n\n/**\n * A channel that fronts one of the runtime's captures: the user's camera or a shared screen. It is the agent's contract\n * for asking to see it, and the capture's policy (`CaptureKind`): the runtime starts the capture only while this channel\n * is in the call and may show the agent pixels.\n *\n * **The agent only asks.** Opening the channel, with a `reason`, is the request: the channel's surface appears where its\n * registry row places it (picture-in-picture) and shows the ask, with the user's choice of turning it on or \"Not now\".\n * Only the user starts or stops the capture; the agent learns what happened from the channel's `status`.\n *\n * Both channels are `on-demand` (listed in the agent's catalog, mounted when opened), `opt-in` (a call has them only when\n * its host or configuration asks for them; the conversations UI brings them, see {@link CONVERSATION_CALL_HOST_CHANNELS})\n * and may show the agent pixels. Their server half is the generic `ClientOnlyChannelServer`.\n */\nexport abstract class RealtimeCaptureChannel extends BaseRealtimeChannelClient<RealtimeCaptureSurfaceComponent> {\n private model: RealtimeCaptureModel | null = null;\n private capturesSub: Subscription | null = null;\n private sourcesSub: Subscription | null = null;\n private surfaceSubs: Subscription[] = [];\n\n /** What makes this channel the camera or the screen share. */\n protected abstract get Text(): CaptureChannelText;\n\n /** The channel's state. Public so the surface and tests share the one instance. */\n public get Model(): RealtimeCaptureModel {\n this.model ??= new RealtimeCaptureModel(this.CaptureKind);\n return this.model;\n }\n\n /** The capture this channel fronts. */\n public override get CaptureKind(): RealtimeCaptureKind {\n return this.Text.Kind;\n }\n\n public get ChannelName(): string {\n return this.Text.Key;\n }\n\n public override get TabTitle(): string {\n return this.Text.DisplayName;\n }\n\n public override get TabIcon(): string {\n return this.Text.TabIcon;\n }\n\n public override GetDescriptor(): RealtimeChannelDescriptor {\n const text = this.Text;\n return {\n Key: text.Key,\n Version: REALTIME_CHANNEL_CONTRACT_VERSION,\n DisplayName: text.DisplayName,\n OwningPackage: '@memberjunction/ng-conversations',\n Instructions: text.Instructions,\n Nouns: this.nouns(text),\n Verbs: [],\n Inputs: {\n type: 'object',\n properties: { reason: { type: 'string', maxLength: 200, description: text.ReasonHint } },\n additionalProperties: false,\n },\n Events: [\n { Name: 'asked', Description: 'Your request is showing to the user.' },\n { Name: 'declined', Description: 'The user said \"Not now\" to your request.' },\n { Name: 'started', Description: 'The user turned it on; you receive it as video.' },\n { Name: 'stopped', Description: 'The user turned it off.' },\n { Name: 'failed', Description: 'It could not start; the payload says why.' },\n ],\n DisplayPolicy: 'on-demand',\n DefaultAvailability: 'opt-in',\n MaxExposure: 'pixels',\n };\n }\n\n public override GetState(): JSONObject {\n return this.Model.ToState();\n }\n\n public override GetSurfaceComponent(): Type<RealtimeCaptureSurfaceComponent> {\n return RealtimeCaptureSurfaceComponent;\n }\n\n protected override OnInitialize(): void {\n this.Model.OnChange((change) => this.onModelChange(change));\n this.Model.SetAgentCanSee(this.Exposure === 'pixels');\n // The sources first, so the model knows whether the capture's frames are sent before it hears the capture is on.\n this.sourcesSub = this.Context?.VideoSources$?.subscribe((sources) => this.Model.FollowVideoSources(sources)) ?? null;\n this.capturesSub =\n this.Context?.Captures$?.subscribe((states) => this.Model.FollowCapture(this.CaptureKind === 'camera' ? states.Camera : states.Screen)) ?? null;\n }\n\n /** The agent's request: opening the channel, again or for the first time, asks the user. */\n protected override OnOpen(inputs: JSONObject): RealtimeChannelVerbResult {\n const reason = typeof inputs['reason'] === 'string' ? inputs['reason'] : null;\n const asked = this.Model.Ask(reason);\n return { Success: true, Result: { asked, status: this.Model.View.Status } };\n }\n\n public override ApplyExposure(settings: ChannelExposureSettings): void {\n super.ApplyExposure(settings);\n this.Model.SetAgentCanSee(this.Exposure === 'pixels');\n }\n\n public override BindSurface(instance: RealtimeCaptureSurfaceComponent): void {\n this.unbindSurfaceOutputs();\n instance.Model = this.Model;\n instance.AgentName = this.Context?.AgentName ?? 'The assistant';\n this.surfaceSubs = [\n instance.StartRequested.subscribe(() => void this.Context?.StartCapture?.(this.CaptureKind)),\n instance.DeclineRequested.subscribe(() => this.Model.Decline()),\n instance.StopRequested.subscribe(() => this.Context?.StopCapture?.(this.CaptureKind)),\n instance.ChangeRequested.subscribe(() => this.changeShare()),\n ];\n }\n\n public override UnbindSurface(): void {\n this.unbindSurfaceOutputs();\n }\n\n public override Dispose(): void {\n this.capturesSub?.unsubscribe();\n this.capturesSub = null;\n this.sourcesSub?.unsubscribe();\n this.sourcesSub = null;\n this.unbindSurfaceOutputs();\n this.Model.OnChange(null);\n super.Dispose();\n }\n\n /** Streams the change's event, and tells the agent (one coalesced note) what changed. */\n private onModelChange(change: RealtimeCaptureChange): void {\n if (change.Event) {\n this.EmitChannelEvent(change.Event.Name, change.Event.Payload);\n }\n this.RecordChange({ Author: change.Event?.Name === 'asked' ? 'agent' : change.Event ? 'user' : 'system' });\n }\n\n /** \"Change\" on a share: stops it and asks the browser's picker again. */\n private changeShare(): void {\n this.Context?.StopCapture?.(this.CaptureKind);\n void this.Context?.StartCapture?.(this.CaptureKind);\n }\n\n private unbindSurfaceOutputs(): void {\n this.surfaceSubs.forEach((sub) => sub.unsubscribe());\n this.surfaceSubs = [];\n }\n\n private nouns(text: CaptureChannelText): RealtimeChannelNoun[] {\n const nouns: RealtimeChannelNoun[] = [\n { Name: 'status', Description: text.Status, Schema: { type: 'string', enum: STATUS_VALUES } },\n { Name: 'reason', Description: 'The reason your standing request shows the user, or empty.', Schema: { type: 'string' } },\n { Name: 'problem', Description: 'Why it last failed to start, in plain words, or empty.', Schema: { type: 'string' } },\n ];\n if (this.CaptureKind === 'screen') {\n nouns.push({\n Name: 'surface',\n Description: 'What the user shares while on: their entire screen, a window or a browser tab (\"unknown\" when the browser does not say).',\n Schema: { type: 'string', enum: ['screen', 'window', 'tab', 'unknown'] },\n });\n }\n return nouns;\n }\n}\n\n/** The CAMERA channel: the agent asks to see the user's camera; only the user turns it on or off. */\n@RegisterClass(BaseRealtimeChannelClient, REALTIME_CAMERA_CHANNEL_CLASS)\nexport class RealtimeCameraChannel extends RealtimeCaptureChannel {\n protected override get Text(): CaptureChannelText {\n return {\n Kind: 'camera',\n Key: REALTIME_CAMERA_CHANNEL_NAME,\n DisplayName: 'Camera',\n TabIcon: 'fa-solid fa-video',\n Instructions:\n \"The user's camera. To see it, open this channel with a short `reason` the user will read (for example, to look at \" +\n 'something they are holding). That only asks: the user decides, and only they turn the camera on or off, so never say ' +\n 'you turned it on. Once it is on you receive it as video. If the user says no, do not ask again unless they bring it up.',\n Status: 'off; asked (your request is showing); starting; on (you receive the camera); failed (see problem).',\n ReasonHint: 'Why you want to see their camera, in a few words they will read.',\n };\n }\n}\n\n/** The SCREEN SHARE channel: the agent asks to see the user's screen; only the user shares or stops. */\n@RegisterClass(BaseRealtimeChannelClient, REALTIME_SCREEN_SHARE_CHANNEL_CLASS)\nexport class RealtimeScreenShareChannel extends RealtimeCaptureChannel {\n protected override get Text(): CaptureChannelText {\n return {\n Kind: 'screen',\n Key: REALTIME_SCREEN_SHARE_CHANNEL_NAME,\n DisplayName: 'Screen share',\n TabIcon: 'fa-solid fa-display',\n Instructions:\n \"The user's screen. To see it, open this channel with a short `reason` the user will read (for example, to look at an \" +\n 'error they mention). That only asks: the user picks a screen, window or tab in their browser and can stop at any ' +\n 'time, so never say you started it. Once shared you receive it as video. If the user says no, do not ask again unless ' +\n 'they bring it up.',\n Status: 'off; asked (your request is showing); starting (the user is choosing); on (you receive it); failed (see problem).',\n ReasonHint: 'Why you want to see their screen, in a few words they will read.',\n };\n }\n}\n\n/**\n * Tree-shaking prevention: the channels are resolved through the ClassFactory by their registry rows' `ClientPluginClass`\n * keys, so this static call keeps their `@RegisterClass` side effects alive.\n */\nexport function LoadRealtimeCaptureChannels(): void {\n // intentional no-op: the import side effect performs the registration\n}\n"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { type Observable } from 'rxjs';
|
|
2
|
+
import type { JSONObject } from '@memberjunction/ai';
|
|
3
|
+
import type { CapturedDisplaySurface, MediaParticipant, MediaVideoSource, VideoSourceState } from '@memberjunction/ai-realtime-client/media';
|
|
4
|
+
import { type RealtimeCaptureKind, type RealtimeCaptureState } from '@memberjunction/realtime-runtime';
|
|
5
|
+
/** Where a capture channel stands, as the agent reads it (its `status` noun) and its surface shows it. */
|
|
6
|
+
export type RealtimeCaptureStatus = 'off' | 'asked' | 'starting' | 'on' | 'failed';
|
|
7
|
+
/** What the capture surface shows. */
|
|
8
|
+
export interface RealtimeCaptureView {
|
|
9
|
+
Kind: RealtimeCaptureKind;
|
|
10
|
+
Status: RealtimeCaptureStatus;
|
|
11
|
+
/** The agent's reason for asking, while its request stands. */
|
|
12
|
+
Reason: string | null;
|
|
13
|
+
/** Why the last start failed, while it stands. */
|
|
14
|
+
Problem: string | null;
|
|
15
|
+
/** The user's camera as `mj-self-view` takes it: while the camera is on, the same object for one stream. */
|
|
16
|
+
Participant: MediaParticipant | null;
|
|
17
|
+
/** The shared surface as `mj-share-preview` takes it: while a share is on, the same object for one stream. */
|
|
18
|
+
Source: MediaVideoSource | null;
|
|
19
|
+
/** What a share shows. */
|
|
20
|
+
Surface: CapturedDisplaySurface;
|
|
21
|
+
/** The shared panel's name, while the user shares one panel of the page; `null` otherwise. */
|
|
22
|
+
PanelLabel: string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Whether the agent sees the capture now: it is on, the channel lets the agent see pixels, and the model is being sent
|
|
25
|
+
* its frames (its source among the session's video sources is on and active, which is what the "Agent can see" chip
|
|
26
|
+
* reads). On a model that takes one video stream, a screen share started after the camera is the one sent, so the camera
|
|
27
|
+
* is not seen until the user picks it again.
|
|
28
|
+
*/
|
|
29
|
+
AgentCanSee: boolean;
|
|
30
|
+
}
|
|
31
|
+
/** The events a capture channel streams, by name. */
|
|
32
|
+
export type RealtimeCaptureEventName = 'asked' | 'declined' | 'started' | 'stopped' | 'failed';
|
|
33
|
+
/** One change: the event to stream, if the change is one. */
|
|
34
|
+
export interface RealtimeCaptureChange {
|
|
35
|
+
Event: {
|
|
36
|
+
Name: RealtimeCaptureEventName;
|
|
37
|
+
Payload: JSONObject;
|
|
38
|
+
} | null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The state of one capture channel (the Camera or the Screen Share channel): the agent's request, the runtime's capture,
|
|
42
|
+
* and whether the agent sees it. Framework-free: the channel feeds it and streams its changes; the surface shows its
|
|
43
|
+
* {@link View$}. It decides nothing about policy: the runtime refuses a capture its channel's policy does not allow, and
|
|
44
|
+
* reports that as a failed capture.
|
|
45
|
+
*/
|
|
46
|
+
export declare class RealtimeCaptureModel {
|
|
47
|
+
readonly Kind: RealtimeCaptureKind;
|
|
48
|
+
private reason;
|
|
49
|
+
private capture;
|
|
50
|
+
private agentCanSee;
|
|
51
|
+
/**
|
|
52
|
+
* Whether the model is being sent this capture's frames: its source is on and active. `null` until the host reports the
|
|
53
|
+
* session's sources ({@link FollowVideoSources}); a host that never does leaves the channel's exposure alone to decide.
|
|
54
|
+
*/
|
|
55
|
+
private framesSent;
|
|
56
|
+
private onStream;
|
|
57
|
+
private readonly view;
|
|
58
|
+
private changeHandler;
|
|
59
|
+
constructor(Kind: RealtimeCaptureKind);
|
|
60
|
+
/** What the surface shows now. */
|
|
61
|
+
get View(): RealtimeCaptureView;
|
|
62
|
+
/** What the surface shows, now and on every change. */
|
|
63
|
+
get View$(): Observable<RealtimeCaptureView>;
|
|
64
|
+
/** Receives every change (one handler; `null` removes it). */
|
|
65
|
+
OnChange(handler: ((change: RealtimeCaptureChange) => void) | null): void;
|
|
66
|
+
/**
|
|
67
|
+
* The agent asks to see the capture. A request while the capture is starting or on changes nothing.
|
|
68
|
+
*
|
|
69
|
+
* @returns Whether the request stands (the user now sees it).
|
|
70
|
+
*/
|
|
71
|
+
Ask(reason: string | null): boolean;
|
|
72
|
+
/** The user said "Not now" to the agent's request. Nothing to decline without one. */
|
|
73
|
+
Decline(): void;
|
|
74
|
+
/**
|
|
75
|
+
* The runtime's capture changed. Turning on answers the agent's request, and so does a camera check that ends with the
|
|
76
|
+
* camera off: the user said not now.
|
|
77
|
+
*/
|
|
78
|
+
FollowCapture(capture: RealtimeCaptureState): void;
|
|
79
|
+
/** Whether the channel lets the agent see pixels (its exposure). */
|
|
80
|
+
SetAgentCanSee(visible: boolean): void;
|
|
81
|
+
/**
|
|
82
|
+
* The session's video sources changed (the runtime's `VideoSources$`). The model is sent this capture's frames only while
|
|
83
|
+
* its source (`REALTIME_CAPTURE_SOURCE_IDS`) is on and active; a capture with no source yet, or none any more, is not
|
|
84
|
+
* sent. Only the view changes: the channel's state is the same, so the change handler hears nothing and the agent is
|
|
85
|
+
* told nothing (the arbiter tells the model what it now sees).
|
|
86
|
+
*/
|
|
87
|
+
FollowVideoSources(sources: readonly VideoSourceState[]): void;
|
|
88
|
+
/** The channel's state as the agent reads it. */
|
|
89
|
+
ToState(): JSONObject;
|
|
90
|
+
/** The event a capture change is, if it is one: started, stopped or failed. */
|
|
91
|
+
private eventFor;
|
|
92
|
+
private publish;
|
|
93
|
+
private buildView;
|
|
94
|
+
private statusOf;
|
|
95
|
+
/** The stream as the surface shows it, built once per stream so a re-render keeps the same objects. */
|
|
96
|
+
private shownStream;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=realtime-capture-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-capture-model.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/capture/realtime-capture-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC7I,OAAO,EAA+B,KAAK,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAEpI,0GAA0G;AAC1G,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,OAAO,GAAG,UAAU,GAAG,IAAI,GAAG,QAAQ,CAAC;AAEnF,sCAAsC;AACtC,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,EAAE,qBAAqB,CAAC;IAC9B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,kDAAkD;IAClD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,4GAA4G;IAC5G,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,8GAA8G;IAC9G,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAChC,0BAA0B;IAC1B,OAAO,EAAE,sBAAsB,CAAC;IAChC,8FAA8F;IAC9F,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;;OAKG;IACH,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,qDAAqD;AACrD,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/F,6DAA6D;AAC7D,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE;QAAE,IAAI,EAAE,wBAAwB,CAAC;QAAC,OAAO,EAAE,UAAU,CAAA;KAAE,GAAG,IAAI,CAAC;CACvE;AAED;;;;;GAKG;AACH,qBAAa,oBAAoB;aAaH,IAAI,EAAE,mBAAmB;IAZrD,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAA2C;IAC1D,OAAO,CAAC,WAAW,CAAS;IAC5B;;;OAGG;IACH,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,QAAQ,CAA+G;IAC/H,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuC;IAC5D,OAAO,CAAC,aAAa,CAA0D;gBAEnD,IAAI,EAAE,mBAAmB;IAIrD,kCAAkC;IAClC,IAAW,IAAI,IAAI,mBAAmB,CAErC;IAED,uDAAuD;IACvD,IAAW,KAAK,IAAI,UAAU,CAAC,mBAAmB,CAAC,CAElD;IAED,8DAA8D;IACvD,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;IAIhF;;;;OAIG;IACI,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;IAS1C,sFAAsF;IAC/E,OAAO,IAAI,IAAI;IAQtB;;;OAGG;IACI,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI;IAczD,oEAAoE;IAC7D,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAO7C;;;;;OAKG;IACI,kBAAkB,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI;IAUrE,iDAAiD;IAC1C,OAAO,IAAI,UAAU;IAS5B,+EAA+E;IAC/E,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,QAAQ;IAOhB,uGAAuG;IACvG,OAAO,CAAC,WAAW;CAcpB"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { BehaviorSubject } from 'rxjs';
|
|
2
|
+
import { REALTIME_CAPTURE_SOURCE_IDS } from '@memberjunction/realtime-runtime';
|
|
3
|
+
/**
|
|
4
|
+
* The state of one capture channel (the Camera or the Screen Share channel): the agent's request, the runtime's capture,
|
|
5
|
+
* and whether the agent sees it. Framework-free: the channel feeds it and streams its changes; the surface shows its
|
|
6
|
+
* {@link View$}. It decides nothing about policy: the runtime refuses a capture its channel's policy does not allow, and
|
|
7
|
+
* reports that as a failed capture.
|
|
8
|
+
*/
|
|
9
|
+
export class RealtimeCaptureModel {
|
|
10
|
+
Kind;
|
|
11
|
+
reason = null;
|
|
12
|
+
capture = { Status: 'off' };
|
|
13
|
+
agentCanSee = false;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the model is being sent this capture's frames: its source is on and active. `null` until the host reports the
|
|
16
|
+
* session's sources ({@link FollowVideoSources}); a host that never does leaves the channel's exposure alone to decide.
|
|
17
|
+
*/
|
|
18
|
+
framesSent = null;
|
|
19
|
+
onStream = null;
|
|
20
|
+
view;
|
|
21
|
+
changeHandler = null;
|
|
22
|
+
constructor(Kind) {
|
|
23
|
+
this.Kind = Kind;
|
|
24
|
+
this.view = new BehaviorSubject(this.buildView());
|
|
25
|
+
}
|
|
26
|
+
/** What the surface shows now. */
|
|
27
|
+
get View() {
|
|
28
|
+
return this.view.value;
|
|
29
|
+
}
|
|
30
|
+
/** What the surface shows, now and on every change. */
|
|
31
|
+
get View$() {
|
|
32
|
+
return this.view.asObservable();
|
|
33
|
+
}
|
|
34
|
+
/** Receives every change (one handler; `null` removes it). */
|
|
35
|
+
OnChange(handler) {
|
|
36
|
+
this.changeHandler = handler;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The agent asks to see the capture. A request while the capture is starting or on changes nothing.
|
|
40
|
+
*
|
|
41
|
+
* @returns Whether the request stands (the user now sees it).
|
|
42
|
+
*/
|
|
43
|
+
Ask(reason) {
|
|
44
|
+
if (this.capture.Status === 'starting' || this.capture.Status === 'on') {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
this.reason = reason?.trim() ?? '';
|
|
48
|
+
this.publish({ Name: 'asked', Payload: this.reason ? { reason: this.reason } : {} });
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
/** The user said "Not now" to the agent's request. Nothing to decline without one. */
|
|
52
|
+
Decline() {
|
|
53
|
+
if (this.reason === null) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
this.reason = null;
|
|
57
|
+
this.publish({ Name: 'declined', Payload: {} });
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The runtime's capture changed. Turning on answers the agent's request, and so does a camera check that ends with the
|
|
61
|
+
* camera off: the user said not now.
|
|
62
|
+
*/
|
|
63
|
+
FollowCapture(capture) {
|
|
64
|
+
const was = this.capture;
|
|
65
|
+
this.capture = capture;
|
|
66
|
+
if (capture.Status === 'on') {
|
|
67
|
+
this.reason = null;
|
|
68
|
+
}
|
|
69
|
+
if (was.Checking && capture.Status === 'off' && this.reason !== null) {
|
|
70
|
+
this.reason = null;
|
|
71
|
+
this.publish({ Name: 'declined', Payload: {} });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.publish(this.eventFor(was.Status, capture));
|
|
75
|
+
}
|
|
76
|
+
/** Whether the channel lets the agent see pixels (its exposure). */
|
|
77
|
+
SetAgentCanSee(visible) {
|
|
78
|
+
if (visible !== this.agentCanSee) {
|
|
79
|
+
this.agentCanSee = visible;
|
|
80
|
+
this.publish(null);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The session's video sources changed (the runtime's `VideoSources$`). The model is sent this capture's frames only while
|
|
85
|
+
* its source (`REALTIME_CAPTURE_SOURCE_IDS`) is on and active; a capture with no source yet, or none any more, is not
|
|
86
|
+
* sent. Only the view changes: the channel's state is the same, so the change handler hears nothing and the agent is
|
|
87
|
+
* told nothing (the arbiter tells the model what it now sees).
|
|
88
|
+
*/
|
|
89
|
+
FollowVideoSources(sources) {
|
|
90
|
+
const sourceId = REALTIME_CAPTURE_SOURCE_IDS[this.Kind];
|
|
91
|
+
const source = sources.find((s) => s.SourceID === sourceId);
|
|
92
|
+
const sent = source !== undefined && source.Enabled && source.Active;
|
|
93
|
+
if (sent !== this.framesSent) {
|
|
94
|
+
this.framesSent = sent;
|
|
95
|
+
this.view.next(this.buildView());
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** The channel's state as the agent reads it. */
|
|
99
|
+
ToState() {
|
|
100
|
+
const view = this.View;
|
|
101
|
+
const state = { status: view.Status, reason: view.Reason ?? '', problem: view.Problem ?? '' };
|
|
102
|
+
if (this.Kind === 'screen') {
|
|
103
|
+
state['surface'] = view.Surface;
|
|
104
|
+
}
|
|
105
|
+
return state;
|
|
106
|
+
}
|
|
107
|
+
/** The event a capture change is, if it is one: started, stopped or failed. */
|
|
108
|
+
eventFor(was, capture) {
|
|
109
|
+
if (capture.Status === 'on' && was !== 'on') {
|
|
110
|
+
return { Name: 'started', Payload: this.Kind === 'screen' ? { surface: capture.Surface ?? 'unknown' } : {} };
|
|
111
|
+
}
|
|
112
|
+
if (capture.Status === 'off' && was === 'on') {
|
|
113
|
+
return { Name: 'stopped', Payload: {} };
|
|
114
|
+
}
|
|
115
|
+
if (capture.Status === 'failed' && was !== 'failed') {
|
|
116
|
+
return { Name: 'failed', Payload: { failure: capture.Failure ?? 'error', message: capture.Message ?? '' } };
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
publish(event) {
|
|
121
|
+
this.view.next(this.buildView());
|
|
122
|
+
this.changeHandler?.({ Event: event });
|
|
123
|
+
}
|
|
124
|
+
buildView() {
|
|
125
|
+
const capture = this.capture;
|
|
126
|
+
const shown = this.shownStream(capture);
|
|
127
|
+
return {
|
|
128
|
+
Kind: this.Kind,
|
|
129
|
+
Status: this.statusOf(capture),
|
|
130
|
+
Reason: this.reason,
|
|
131
|
+
Problem: capture.Status === 'failed' ? (capture.Message ?? 'The capture could not start.') : null,
|
|
132
|
+
Participant: shown?.Participant ?? null,
|
|
133
|
+
Source: shown?.Source ?? null,
|
|
134
|
+
Surface: capture.Surface ?? 'unknown',
|
|
135
|
+
PanelLabel: capture.PanelLabel ?? null,
|
|
136
|
+
AgentCanSee: capture.Status === 'on' && this.agentCanSee && (this.framesSent ?? true),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
statusOf(capture) {
|
|
140
|
+
if (capture.Status === 'off') {
|
|
141
|
+
return this.reason !== null ? 'asked' : 'off';
|
|
142
|
+
}
|
|
143
|
+
return capture.Status;
|
|
144
|
+
}
|
|
145
|
+
/** The stream as the surface shows it, built once per stream so a re-render keeps the same objects. */
|
|
146
|
+
shownStream(capture) {
|
|
147
|
+
if (capture.Status !== 'on' || !capture.Stream) {
|
|
148
|
+
this.onStream = null;
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
if (this.onStream?.Stream !== capture.Stream) {
|
|
152
|
+
const video = { Kind: 'stream', Stream: capture.Stream };
|
|
153
|
+
this.onStream =
|
|
154
|
+
this.Kind === 'camera'
|
|
155
|
+
? { Stream: capture.Stream, Participant: { Identity: 'self', DisplayName: 'You', Role: 'self', IsSpeaking: false, Video: { camera: video } }, Source: null }
|
|
156
|
+
: { Stream: capture.Stream, Participant: null, Source: video };
|
|
157
|
+
}
|
|
158
|
+
return this.onStream;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=realtime-capture-model.js.map
|