@memberjunction/ng-conversations 5.40.2 → 5.42.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/README.md +57 -0
- package/dist/__tests__/channel-optional-surface.test.d.ts +2 -0
- package/dist/__tests__/channel-optional-surface.test.d.ts.map +1 -0
- package/dist/__tests__/channel-optional-surface.test.js +53 -0
- package/dist/__tests__/channel-optional-surface.test.js.map +1 -0
- package/dist/__tests__/chat-events.test.d.ts +14 -0
- package/dist/__tests__/chat-events.test.d.ts.map +1 -0
- package/dist/__tests__/chat-events.test.js +109 -0
- package/dist/__tests__/chat-events.test.js.map +1 -0
- package/dist/__tests__/conversation-naming.test.d.ts +2 -0
- package/dist/__tests__/conversation-naming.test.d.ts.map +1 -0
- package/dist/__tests__/conversation-naming.test.js +110 -0
- package/dist/__tests__/conversation-naming.test.js.map +1 -0
- package/dist/__tests__/delegation-result-parser.test.d.ts +2 -0
- package/dist/__tests__/delegation-result-parser.test.d.ts.map +1 -0
- package/dist/__tests__/delegation-result-parser.test.js +107 -0
- package/dist/__tests__/delegation-result-parser.test.js.map +1 -0
- package/dist/__tests__/event-wiring.test.d.ts +15 -0
- package/dist/__tests__/event-wiring.test.d.ts.map +1 -0
- package/dist/__tests__/event-wiring.test.js +100 -0
- package/dist/__tests__/event-wiring.test.js.map +1 -0
- package/dist/__tests__/narration-template.test.d.ts +2 -0
- package/dist/__tests__/narration-template.test.d.ts.map +1 -0
- package/dist/__tests__/narration-template.test.js +76 -0
- package/dist/__tests__/narration-template.test.js.map +1 -0
- package/dist/__tests__/realtime-agent-picker-models.test.d.ts +2 -0
- package/dist/__tests__/realtime-agent-picker-models.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-agent-picker-models.test.js +49 -0
- package/dist/__tests__/realtime-agent-picker-models.test.js.map +1 -0
- package/dist/__tests__/realtime-audio-visuals.test.d.ts +2 -0
- package/dist/__tests__/realtime-audio-visuals.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-audio-visuals.test.js +123 -0
- package/dist/__tests__/realtime-audio-visuals.test.js.map +1 -0
- package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts +2 -0
- package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-delegation-card-cancel.test.js +48 -0
- package/dist/__tests__/realtime-delegation-card-cancel.test.js.map +1 -0
- package/dist/__tests__/realtime-disclosure.test.d.ts +2 -0
- package/dist/__tests__/realtime-disclosure.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-disclosure.test.js +164 -0
- package/dist/__tests__/realtime-disclosure.test.js.map +1 -0
- package/dist/__tests__/realtime-pairing.test.d.ts +2 -0
- package/dist/__tests__/realtime-pairing.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-pairing.test.js +207 -0
- package/dist/__tests__/realtime-pairing.test.js.map +1 -0
- package/dist/__tests__/realtime-review-lifecycle.test.d.ts +2 -0
- package/dist/__tests__/realtime-review-lifecycle.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-review-lifecycle.test.js +154 -0
- package/dist/__tests__/realtime-review-lifecycle.test.js.map +1 -0
- package/dist/__tests__/realtime-session-cancel-usage.test.d.ts +2 -0
- package/dist/__tests__/realtime-session-cancel-usage.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-session-cancel-usage.test.js +230 -0
- package/dist/__tests__/realtime-session-cancel-usage.test.js.map +1 -0
- package/dist/__tests__/realtime-session-channels.test.d.ts +2 -0
- package/dist/__tests__/realtime-session-channels.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-session-channels.test.js +252 -0
- package/dist/__tests__/realtime-session-channels.test.js.map +1 -0
- package/dist/__tests__/realtime-session-client-tools.test.d.ts +2 -0
- package/dist/__tests__/realtime-session-client-tools.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-session-client-tools.test.js +103 -0
- package/dist/__tests__/realtime-session-client-tools.test.js.map +1 -0
- package/dist/__tests__/realtime-session-minimized.test.d.ts +2 -0
- package/dist/__tests__/realtime-session-minimized.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-session-minimized.test.js +32 -0
- package/dist/__tests__/realtime-session-minimized.test.js.map +1 -0
- package/dist/__tests__/realtime-session-mint.test.d.ts +2 -0
- package/dist/__tests__/realtime-session-mint.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-session-mint.test.js +69 -0
- package/dist/__tests__/realtime-session-mint.test.js.map +1 -0
- package/dist/__tests__/realtime-session-policy.test.d.ts +2 -0
- package/dist/__tests__/realtime-session-policy.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-session-policy.test.js +303 -0
- package/dist/__tests__/realtime-session-policy.test.js.map +1 -0
- package/dist/__tests__/realtime-session-review.service.test.d.ts +2 -0
- package/dist/__tests__/realtime-session-review.service.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-session-review.service.test.js +743 -0
- package/dist/__tests__/realtime-session-review.service.test.js.map +1 -0
- package/dist/__tests__/realtime-session-state.test.d.ts +2 -0
- package/dist/__tests__/realtime-session-state.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-session-state.test.js +83 -0
- package/dist/__tests__/realtime-session-state.test.js.map +1 -0
- package/dist/__tests__/realtime-session-timeline-card.test.d.ts +2 -0
- package/dist/__tests__/realtime-session-timeline-card.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-session-timeline-card.test.js +106 -0
- package/dist/__tests__/realtime-session-timeline-card.test.js.map +1 -0
- package/dist/__tests__/realtime-session-timeline.test.d.ts +2 -0
- package/dist/__tests__/realtime-session-timeline.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-session-timeline.test.js +142 -0
- package/dist/__tests__/realtime-session-timeline.test.js.map +1 -0
- package/dist/__tests__/realtime-sessions-adapter.test.d.ts +19 -0
- package/dist/__tests__/realtime-sessions-adapter.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-sessions-adapter.test.js +188 -0
- package/dist/__tests__/realtime-sessions-adapter.test.js.map +1 -0
- package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts +2 -0
- package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-surface-panel-prefs.test.js +100 -0
- package/dist/__tests__/realtime-surface-panel-prefs.test.js.map +1 -0
- package/dist/__tests__/realtime-surface-tabs-model.test.d.ts +2 -0
- package/dist/__tests__/realtime-surface-tabs-model.test.d.ts.map +1 -0
- package/dist/__tests__/realtime-surface-tabs-model.test.js +193 -0
- package/dist/__tests__/realtime-surface-tabs-model.test.js.map +1 -0
- package/dist/__tests__/remote-browser-audio-player.test.d.ts +2 -0
- package/dist/__tests__/remote-browser-audio-player.test.d.ts.map +1 -0
- package/dist/__tests__/remote-browser-audio-player.test.js +137 -0
- package/dist/__tests__/remote-browser-audio-player.test.js.map +1 -0
- package/dist/__tests__/remote-browser-channel.test.d.ts +2 -0
- package/dist/__tests__/remote-browser-channel.test.d.ts.map +1 -0
- package/dist/__tests__/remote-browser-channel.test.js +585 -0
- package/dist/__tests__/remote-browser-channel.test.js.map +1 -0
- package/dist/__tests__/slot-defaults.test.d.ts +24 -0
- package/dist/__tests__/slot-defaults.test.d.ts.map +1 -0
- package/dist/__tests__/slot-defaults.test.js +63 -0
- package/dist/__tests__/slot-defaults.test.js.map +1 -0
- package/dist/__tests__/user-authorization.test.d.ts +2 -0
- package/dist/__tests__/user-authorization.test.d.ts.map +1 -0
- package/dist/__tests__/user-authorization.test.js +97 -0
- package/dist/__tests__/user-authorization.test.js.map +1 -0
- package/dist/__tests__/voice-session-narration.test.d.ts +2 -0
- package/dist/__tests__/voice-session-narration.test.d.ts.map +1 -0
- package/dist/__tests__/voice-session-narration.test.js +609 -0
- package/dist/__tests__/voice-session-narration.test.js.map +1 -0
- package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts +2 -0
- package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts.map +1 -0
- package/dist/__tests__/whiteboard-artifact-viewer.test.js +101 -0
- package/dist/__tests__/whiteboard-artifact-viewer.test.js.map +1 -0
- package/dist/__tests__/whiteboard-channel.test.d.ts +2 -0
- package/dist/__tests__/whiteboard-channel.test.d.ts.map +1 -0
- package/dist/__tests__/whiteboard-channel.test.js +260 -0
- package/dist/__tests__/whiteboard-channel.test.js.map +1 -0
- package/dist/__tests__/whiteboard-restore-state.test.d.ts +2 -0
- package/dist/__tests__/whiteboard-restore-state.test.d.ts.map +1 -0
- package/dist/__tests__/whiteboard-restore-state.test.js +108 -0
- package/dist/__tests__/whiteboard-restore-state.test.js.map +1 -0
- package/dist/lib/components/collection/collections-full-view.component.d.ts +105 -2
- package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.js +1378 -489
- package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +209 -3
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +924 -350
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.d.ts +98 -5
- package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.js +1102 -401
- package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
- package/dist/lib/components/mention/mention-dropdown.component.js +35 -17
- package/dist/lib/components/mention/mention-dropdown.component.js.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.d.ts +4 -0
- package/dist/lib/components/mention/mention-editor.component.d.ts.map +1 -1
- package/dist/lib/components/mention/mention-editor.component.js +43 -19
- package/dist/lib/components/mention/mention-editor.component.js.map +1 -1
- package/dist/lib/components/message/message-input-box.component.d.ts +17 -1
- package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input-box.component.js +73 -15
- package/dist/lib/components/message/message-input-box.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +142 -6
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +328 -82
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +28 -3
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +180 -108
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +81 -2
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +252 -87
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/project/project-form-modal.component.d.ts +5 -1
- package/dist/lib/components/project/project-form-modal.component.d.ts.map +1 -1
- package/dist/lib/components/project/project-form-modal.component.js +104 -85
- package/dist/lib/components/project/project-form-modal.component.js.map +1 -1
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +304 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +1 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +198 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +1 -0
- package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts +25 -0
- package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.js +140 -0
- package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.js.map +1 -0
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +35 -0
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +58 -0
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +63 -0
- package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-activity-rail.component.js +260 -0
- package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +117 -0
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-banner.component.js +504 -0
- package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +179 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.js +634 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +97 -0
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-audio-visuals.js +139 -0
- package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -0
- package/dist/lib/components/realtime/realtime-channel-strip.component.d.ts +29 -0
- package/dist/lib/components/realtime/realtime-channel-strip.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-channel-strip.component.js +69 -0
- package/dist/lib/components/realtime/realtime-channel-strip.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-composer.component.d.ts +65 -0
- package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-composer.component.js +256 -0
- package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +71 -0
- package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-delegation-card.component.js +324 -0
- package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-disclosure.d.ts +135 -0
- package/dist/lib/components/realtime/realtime-disclosure.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-disclosure.js +188 -0
- package/dist/lib/components/realtime/realtime-disclosure.js.map +1 -0
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +491 -0
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +1274 -0
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-session-state.d.ts +191 -0
- package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-session-state.js +244 -0
- package/dist/lib/components/realtime/realtime-session-state.js.map +1 -0
- package/dist/lib/components/realtime/realtime-session-thread.component.d.ts +56 -0
- package/dist/lib/components/realtime/realtime-session-thread.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-session-thread.component.js +246 -0
- package/dist/lib/components/realtime/realtime-session-thread.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts +51 -0
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.js +193 -0
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-panel-prefs.d.ts +77 -0
- package/dist/lib/components/realtime/realtime-surface-panel-prefs.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-panel-prefs.js +114 -0
- package/dist/lib/components/realtime/realtime-surface-panel-prefs.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +173 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js +496 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +181 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js +223 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.d.ts +163 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.d.ts.map +1 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.js +309 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-audio-player.js.map +1 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +201 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +681 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +379 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +914 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-tools.d.ts +87 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-tools.d.ts.map +1 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-tools.js +223 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-tools.js.map +1 -0
- package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.d.ts +48 -0
- package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.js +180 -0
- package/dist/lib/components/realtime/whiteboard/whiteboard-artifact-viewer.component.js.map +1 -0
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +119 -0
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +274 -0
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -0
- package/dist/lib/components/slots/mj-chat-agent-presence-default.component.d.ts +11 -0
- package/dist/lib/components/slots/mj-chat-agent-presence-default.component.d.ts.map +1 -0
- package/dist/lib/components/slots/mj-chat-agent-presence-default.component.js +98 -0
- package/dist/lib/components/slots/mj-chat-agent-presence-default.component.js.map +1 -0
- package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.d.ts +9 -0
- package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.d.ts.map +1 -0
- package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.js +35 -0
- package/dist/lib/components/slots/mj-chat-demonstration-surface-default.component.js.map +1 -0
- package/dist/lib/components/slots/mj-chat-empty-state-default.component.d.ts +28 -0
- package/dist/lib/components/slots/mj-chat-empty-state-default.component.d.ts.map +1 -0
- package/dist/lib/components/slots/mj-chat-empty-state-default.component.js +104 -0
- package/dist/lib/components/slots/mj-chat-empty-state-default.component.js.map +1 -0
- package/dist/lib/components/slots/mj-chat-header-default.component.d.ts +11 -0
- package/dist/lib/components/slots/mj-chat-header-default.component.d.ts.map +1 -0
- package/dist/lib/components/slots/mj-chat-header-default.component.js +103 -0
- package/dist/lib/components/slots/mj-chat-header-default.component.js.map +1 -0
- package/dist/lib/components/slots/mj-chat-message-bubble-default.component.d.ts +15 -0
- package/dist/lib/components/slots/mj-chat-message-bubble-default.component.d.ts.map +1 -0
- package/dist/lib/components/slots/mj-chat-message-bubble-default.component.js +73 -0
- package/dist/lib/components/slots/mj-chat-message-bubble-default.component.js.map +1 -0
- package/dist/lib/components/slots/mj-chat-message-extra-default.component.d.ts +9 -0
- package/dist/lib/components/slots/mj-chat-message-extra-default.component.d.ts.map +1 -0
- package/dist/lib/components/slots/mj-chat-message-extra-default.component.js +34 -0
- package/dist/lib/components/slots/mj-chat-message-extra-default.component.js.map +1 -0
- package/dist/lib/components/slots/slot-interfaces.d.ts +95 -0
- package/dist/lib/components/slots/slot-interfaces.d.ts.map +1 -0
- package/dist/lib/components/slots/slot-interfaces.js +18 -0
- package/dist/lib/components/slots/slot-interfaces.js.map +1 -0
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +15 -0
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +41 -12
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/conversations.module.d.ts +12 -1
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +93 -5
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/directives/chat-slot.directive.d.ts +44 -0
- package/dist/lib/directives/chat-slot.directive.d.ts.map +1 -0
- package/dist/lib/directives/chat-slot.directive.js +54 -0
- package/dist/lib/directives/chat-slot.directive.js.map +1 -0
- package/dist/lib/events/chat-events.d.ts +137 -0
- package/dist/lib/events/chat-events.d.ts.map +1 -0
- package/dist/lib/events/chat-events.js +189 -0
- package/dist/lib/events/chat-events.js.map +1 -0
- package/dist/lib/models/conversation-state.model.d.ts +2 -1
- 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/artifact-state.service.d.ts +1 -1
- package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-state.service.js +29 -7
- package/dist/lib/services/artifact-state.service.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +60 -74
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +100 -313
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-bridge.service.d.ts +11 -70
- package/dist/lib/services/conversation-bridge.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-bridge.service.js +51 -85
- package/dist/lib/services/conversation-bridge.service.js.map +1 -1
- package/dist/lib/services/conversation-naming.d.ts +63 -0
- package/dist/lib/services/conversation-naming.d.ts.map +1 -0
- package/dist/lib/services/conversation-naming.js +58 -0
- package/dist/lib/services/conversation-naming.js.map +1 -0
- package/dist/lib/services/conversation-streaming.service.d.ts +24 -154
- package/dist/lib/services/conversation-streaming.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-streaming.service.js +39 -361
- package/dist/lib/services/conversation-streaming.service.js.map +1 -1
- package/dist/lib/services/conversations-runtime-bootstrap.service.d.ts +10 -0
- package/dist/lib/services/conversations-runtime-bootstrap.service.d.ts.map +1 -0
- package/dist/lib/services/conversations-runtime-bootstrap.service.js +104 -0
- package/dist/lib/services/conversations-runtime-bootstrap.service.js.map +1 -0
- package/dist/lib/services/delegation-result-parser.d.ts +45 -0
- package/dist/lib/services/delegation-result-parser.d.ts.map +1 -0
- package/dist/lib/services/delegation-result-parser.js +48 -0
- package/dist/lib/services/delegation-result-parser.js.map +1 -0
- package/dist/lib/services/mention-autocomplete.service.d.ts +19 -4
- package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
- package/dist/lib/services/mention-autocomplete.service.js +65 -4
- package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
- package/dist/lib/services/mention-parser.service.d.ts +8 -53
- package/dist/lib/services/mention-parser.service.d.ts.map +1 -1
- package/dist/lib/services/mention-parser.service.js +32 -243
- package/dist/lib/services/mention-parser.service.js.map +1 -1
- package/dist/lib/services/narration-template.d.ts +42 -0
- package/dist/lib/services/narration-template.d.ts.map +1 -0
- package/dist/lib/services/narration-template.js +73 -0
- package/dist/lib/services/narration-template.js.map +1 -0
- package/dist/lib/services/realtime-pairing.d.ts +121 -0
- package/dist/lib/services/realtime-pairing.d.ts.map +1 -0
- package/dist/lib/services/realtime-pairing.js +160 -0
- package/dist/lib/services/realtime-pairing.js.map +1 -0
- package/dist/lib/services/realtime-session-review.service.d.ts +233 -0
- package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -0
- package/dist/lib/services/realtime-session-review.service.js +417 -0
- package/dist/lib/services/realtime-session-review.service.js.map +1 -0
- package/dist/lib/services/realtime-session.service.d.ts +739 -0
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -0
- package/dist/lib/services/realtime-session.service.js +1647 -0
- package/dist/lib/services/realtime-session.service.js.map +1 -0
- package/dist/lib/services/realtime-sessions-adapter.d.ts +54 -0
- package/dist/lib/services/realtime-sessions-adapter.d.ts.map +1 -0
- package/dist/lib/services/realtime-sessions-adapter.js +154 -0
- package/dist/lib/services/realtime-sessions-adapter.js.map +1 -0
- package/dist/lib/services/user-authorization.d.ts +67 -0
- package/dist/lib/services/user-authorization.d.ts.map +1 -0
- package/dist/lib/services/user-authorization.js +66 -0
- package/dist/lib/services/user-authorization.js.map +1 -0
- package/dist/lib/utils/realtime-session-timeline.d.ts +84 -0
- package/dist/lib/utils/realtime-session-timeline.d.ts.map +1 -0
- package/dist/lib/utils/realtime-session-timeline.js +94 -0
- package/dist/lib/utils/realtime-session-timeline.js.map +1 -0
- package/dist/public-api.d.ts +41 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +50 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +27 -24
- package/dist/__tests__/conversation-bridge.service.test.d.ts +0 -2
- package/dist/__tests__/conversation-bridge.service.test.d.ts.map +0 -1
- package/dist/__tests__/conversation-bridge.service.test.js +0 -98
- package/dist/__tests__/conversation-bridge.service.test.js.map +0 -1
- package/dist/__tests__/mention-parser.test.d.ts +0 -2
- package/dist/__tests__/mention-parser.test.d.ts.map +0 -1
- package/dist/__tests__/mention-parser.test.js +0 -154
- package/dist/__tests__/mention-parser.test.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-form-modal.component.js","sourceRoot":"","sources":["../../../../src/lib/components/project/project-form-modal.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { MJDialogRef } from '@memberjunction/ng-ui-components';\nimport { MJProjectEntity } from '@memberjunction/core-entities';\nimport { UserInfo, Metadata } from '@memberjunction/core';\n\nexport interface ProjectFormData {\n name: string;\n description: string;\n color: string;\n icon: string;\n}\n\nconst DEFAULT_PROJECT_COLORS = [\n '#0076B6', // MJ Blue\n '#F44336', // Red\n '#E91E63', // Pink\n '#9C27B0', // Purple\n '#673AB7', // Deep Purple\n '#3F51B5', // Indigo\n '#2196F3', // Blue\n '#03A9F4', // Light Blue\n '#00BCD4', // Cyan\n '#009688', // Teal\n '#4CAF50', // Green\n '#8BC34A', // Light Green\n '#CDDC39', // Lime\n '#FFEB3B', // Yellow\n '#FFC107', // Amber\n '#FF9800', // Orange\n '#FF5722', // Deep Orange\n '#795548', // Brown\n '#607D8B', // Blue Grey\n '#9E9E9E' // Grey\n];\n\nconst DEFAULT_PROJECT_ICONS = [\n 'fa-folder',\n 'fa-folder-open',\n 'fa-briefcase',\n 'fa-project-diagram',\n 'fa-chart-line',\n 'fa-tasks',\n 'fa-clipboard-list',\n 'fa-bullseye',\n 'fa-rocket',\n 'fa-lightbulb',\n 'fa-brain',\n 'fa-cogs',\n 'fa-code',\n 'fa-database',\n 'fa-server',\n 'fa-cloud',\n 'fa-mobile-alt',\n 'fa-desktop',\n 'fa-globe',\n 'fa-users'\n];\n\n@Component({\n standalone: false,\n selector: 'mj-project-form-modal',\n template: `\n <mj-dialog\n [Title]=\"isEditMode ? 'Edit Project' : 'New Project'\"\n [Width]=\"600\"\n [MinWidth]=\"400\"\n [Visible]=\"true\"\n (Close)=\"onCancel()\">\n\n <div class=\"project-form\">\n <!-- Name Input -->\n <div class=\"form-field\">\n <label for=\"projectName\" class=\"required\">\n Project Name\n </label>\n <input\n id=\"projectName\"\n type=\"text\"\n [(ngModel)]=\"formData.name\"\n placeholder=\"Enter project name\"\n class=\"mj-textbox full-width\"\n (keydown.enter)=\"onSave()\"\n autofocus />\n @if (showNameError) {\n <div class=\"error-message\">Project name is required</div>\n }\n </div>\n\n <!-- Description Textarea -->\n <div class=\"form-field\">\n <label for=\"projectDescription\">\n Description\n </label>\n <textarea\n id=\"projectDescription\"\n [(ngModel)]=\"formData.description\"\n placeholder=\"Enter project description (optional)\"\n class=\"mj-textarea full-width\"\n rows=\"3\"></textarea>\n </div>\n\n <!-- Color Picker -->\n <div class=\"form-field\">\n <label>Color</label>\n <div class=\"color-picker-section\">\n <div class=\"color-palette\">\n @for (color of availableColors; track color) {\n <button\n type=\"button\"\n class=\"color-swatch\"\n [class.selected]=\"formData.color === color\"\n [style.backgroundColor]=\"color\"\n (click)=\"selectColor(color)\"\n [title]=\"color\">\n </button>\n }\n </div>\n <div class=\"custom-color-input\">\n <label for=\"customColor\">Custom:</label>\n <input\n id=\"customColor\"\n type=\"color\"\n [(ngModel)]=\"formData.color\"\n class=\"custom-color-picker\" />\n <span class=\"color-value\">{{ formData.color }}</span>\n </div>\n </div>\n </div>\n\n <!-- Icon Selector -->\n <div class=\"form-field\">\n <label>Icon</label>\n <div class=\"icon-selector-section\">\n <div class=\"selected-icon-preview\">\n <i class=\"fa-solid {{ formData.icon }}\" [style.color]=\"formData.color\"></i>\n <span>{{ formData.icon }}</span>\n </div>\n <div class=\"icon-grid\">\n @for (icon of availableIcons; track icon) {\n <button\n type=\"button\"\n class=\"icon-option\"\n [class.selected]=\"formData.icon === icon\"\n (click)=\"selectIcon(icon)\"\n [title]=\"icon\">\n <i class=\"fa-solid {{ icon }}\"></i>\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n\n <mj-dialog-actions>\n <button mjButton (click)=\"onCancel()\">Cancel</button>\n <button mjButton variant=\"primary\" (click)=\"onSave()\">\n {{ isEditMode ? 'Save' : 'Create' }}\n </button>\n </mj-dialog-actions>\n </mj-dialog>\n `,\n styles: [`\n .project-form {\n padding: 16px;\n }\n\n .form-field {\n margin-bottom: 20px;\n }\n\n .form-field label {\n display: block;\n margin-bottom: 8px;\n font-weight: 500;\n font-size: 14px;\n color: #333;\n }\n\n .form-field label.required::after {\n content: '*';\n color: #F44336;\n margin-left: 4px;\n }\n\n .full-width {\n width: 100%;\n }\n\n .error-message {\n color: #F44336;\n font-size: 12px;\n margin-top: 4px;\n }\n\n /* Color Picker Styles */\n .color-picker-section {\n border: 1px solid #D9D9D9;\n border-radius: 4px;\n padding: 12px;\n background: #F9F9F9;\n }\n\n .color-palette {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .color-swatch {\n width: 100%;\n aspect-ratio: 1;\n border: 2px solid transparent;\n border-radius: 4px;\n cursor: pointer;\n transition: all 150ms ease;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n }\n\n .color-swatch:hover {\n transform: scale(1.1);\n box-shadow: 0 2px 6px rgba(0,0,0,0.2);\n }\n\n .color-swatch.selected {\n border-color: #0076B6;\n box-shadow: 0 0 0 2px #fff, 0 0 0 4px #0076B6;\n }\n\n .custom-color-input {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 12px;\n border-top: 1px solid #D9D9D9;\n }\n\n .custom-color-input label {\n margin: 0;\n font-size: 13px;\n }\n\n .custom-color-picker {\n width: 50px;\n height: 32px;\n border: 1px solid #D9D9D9;\n border-radius: 4px;\n cursor: pointer;\n }\n\n .color-value {\n font-family: monospace;\n font-size: 13px;\n color: #666;\n }\n\n /* Icon Selector Styles */\n .icon-selector-section {\n border: 1px solid #D9D9D9;\n border-radius: 4px;\n padding: 12px;\n background: #F9F9F9;\n }\n\n .selected-icon-preview {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: white;\n border: 1px solid #D9D9D9;\n border-radius: 4px;\n margin-bottom: 12px;\n }\n\n .selected-icon-preview i {\n font-size: 24px;\n }\n\n .selected-icon-preview span {\n font-family: monospace;\n font-size: 13px;\n color: #666;\n }\n\n .icon-grid {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 6px;\n max-height: 200px;\n overflow-y: auto;\n padding: 4px;\n }\n\n .icon-option {\n aspect-ratio: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid #D9D9D9;\n background: white;\n border-radius: 4px;\n cursor: pointer;\n transition: all 150ms ease;\n }\n\n .icon-option:hover {\n background: #F0F0F0;\n border-color: #0076B6;\n transform: scale(1.05);\n }\n\n .icon-option.selected {\n background: #E3F2FD;\n border-color: #0076B6;\n border-width: 2px;\n }\n\n .icon-option i {\n font-size: 18px;\n color: #333;\n }\n\n /* Scrollbar Styles */\n .icon-grid::-webkit-scrollbar {\n width: 8px;\n }\n\n .icon-grid::-webkit-scrollbar-track {\n background: #F0F0F0;\n border-radius: 4px;\n }\n\n .icon-grid::-webkit-scrollbar-thumb {\n background: #D9D9D9;\n border-radius: 4px;\n }\n\n .icon-grid::-webkit-scrollbar-thumb:hover {\n background: #BFBFBF;\n }\n `]\n})\nexport class ProjectFormModalComponent extends BaseAngularComponent implements OnInit {\n @Input() dialogRef!: MJDialogRef;\n @Input() project: MJProjectEntity | null = null;\n @Input() environmentId!: string;\n @Input() currentUser!: UserInfo;\n\n @Output() projectSaved = new EventEmitter<MJProjectEntity>();\n\n public formData: ProjectFormData = {\n name: '',\n description: '',\n color: '#0076B6',\n icon: 'fa-folder'\n };\n\n public showNameError = false;\n public isEditMode = false;\n public availableColors = DEFAULT_PROJECT_COLORS;\n public availableIcons = DEFAULT_PROJECT_ICONS;\n\n constructor(private cdr: ChangeDetectorRef) {\n super();}\n\n ngOnInit(): void {\n this.isEditMode = this.project != null;\n\n if (this.project) {\n this.loadProjectData();\n }\n }\n\n private loadProjectData(): void {\n if (!this.project) return;\n\n this.formData = {\n name: this.project.Name || '',\n description: this.project.Description || '',\n color: this.project.Color || '#0076B6',\n icon: this.project.Icon || 'fa-folder'\n };\n }\n\n selectColor(color: string): void {\n this.formData.color = color;\n this.cdr.detectChanges();\n }\n\n selectIcon(icon: string): void {\n this.formData.icon = icon;\n this.cdr.detectChanges();\n }\n\n async onSave(): Promise<void> {\n // Validate\n if (!this.formData.name.trim()) {\n this.showNameError = true;\n this.cdr.detectChanges();\n return;\n }\n\n this.showNameError = false;\n\n try {\n const md = this.ProviderToUse;\n const project = this.project || await md.GetEntityObject<MJProjectEntity>('MJ: Projects', this.currentUser);\n\n project.Name = this.formData.name.trim();\n project.Description = this.formData.description.trim() || null;\n project.Color = this.formData.color;\n project.Icon = this.formData.icon;\n\n if (!this.isEditMode) {\n project.EnvironmentID = this.environmentId;\n project.IsArchived = false;\n }\n\n const saved = await project.Save();\n if (saved) {\n this.projectSaved.emit(project);\n this.dialogRef.Close();\n } else {\n throw new Error('Failed to save project');\n }\n } catch (error) {\n console.error('Error saving project:', error);\n alert('Failed to save project. Please try again.');\n }\n }\n\n onCancel(): void {\n this.dialogRef.Close();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"project-form-modal.component.js","sourceRoot":"","sources":["../../../../src/lib/components/project/project-form-modal.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { MJDialogRef } from '@memberjunction/ng-ui-components';\nimport { MJProjectEntity } from '@memberjunction/core-entities';\nimport { UserInfo, Metadata } from '@memberjunction/core';\n\nexport interface ProjectFormData {\n name: string;\n description: string;\n color: string;\n icon: string;\n}\n\nconst DEFAULT_PROJECT_COLORS = [\n '#0076B6', // MJ Blue\n '#F44336', // Red\n '#E91E63', // Pink\n '#9C27B0', // Purple\n '#673AB7', // Deep Purple\n '#3F51B5', // Indigo\n '#2196F3', // Blue\n '#03A9F4', // Light Blue\n '#00BCD4', // Cyan\n '#009688', // Teal\n '#4CAF50', // Green\n '#8BC34A', // Light Green\n '#CDDC39', // Lime\n '#FFEB3B', // Yellow\n '#FFC107', // Amber\n '#FF9800', // Orange\n '#FF5722', // Deep Orange\n '#795548', // Brown\n '#607D8B', // Blue Grey\n '#9E9E9E' // Grey\n];\n\nconst DEFAULT_PROJECT_ICONS = [\n 'fa-folder',\n 'fa-folder-open',\n 'fa-briefcase',\n 'fa-project-diagram',\n 'fa-chart-line',\n 'fa-tasks',\n 'fa-clipboard-list',\n 'fa-bullseye',\n 'fa-rocket',\n 'fa-lightbulb',\n 'fa-brain',\n 'fa-cogs',\n 'fa-code',\n 'fa-database',\n 'fa-server',\n 'fa-cloud',\n 'fa-mobile-alt',\n 'fa-desktop',\n 'fa-globe',\n 'fa-users'\n];\n\n@Component({\n standalone: false,\n selector: 'mj-project-form-modal',\n template: `\n <mj-dialog\n [Title]=\"isEditMode ? 'Edit Folder' : 'New Folder'\"\n [Width]=\"560\"\n [MinWidth]=\"400\"\n [Visible]=\"true\"\n (Close)=\"onCancel()\">\n\n <div class=\"project-form\">\n <!-- Live preview chip -->\n <div class=\"folder-preview\">\n <span class=\"folder-preview-chip\" [style.backgroundColor]=\"chipBackground\" [style.color]=\"formData.color\">\n <i class=\"fa-solid {{ formData.icon }}\"></i>\n </span>\n <span class=\"folder-preview-name\">{{ formData.name.trim() || 'Untitled folder' }}</span>\n </div>\n\n <!-- Name Input -->\n <div class=\"form-field\">\n <label for=\"projectName\" class=\"required\">\n Folder Name\n </label>\n <input\n id=\"projectName\"\n type=\"text\"\n [(ngModel)]=\"formData.name\"\n placeholder=\"e.g. Client work, Research, Ideas\"\n class=\"mj-input full-width\"\n (keydown.enter)=\"onSave()\"\n autofocus />\n @if (showNameError) {\n <div class=\"error-message\">Folder name is required</div>\n }\n </div>\n\n <!-- Description Textarea -->\n <div class=\"form-field\">\n <label for=\"projectDescription\">\n Description\n </label>\n <textarea\n id=\"projectDescription\"\n [(ngModel)]=\"formData.description\"\n placeholder=\"What goes in this folder? (optional)\"\n class=\"mj-textarea full-width\"\n rows=\"2\"></textarea>\n </div>\n\n <!-- Color Picker -->\n <div class=\"form-field\">\n <label>Color</label>\n <div class=\"color-picker-section\">\n <div class=\"color-palette\">\n @for (color of availableColors; track color) {\n <button\n type=\"button\"\n class=\"color-swatch\"\n [class.selected]=\"formData.color === color\"\n [style.backgroundColor]=\"color\"\n (click)=\"selectColor(color)\"\n [title]=\"color\">\n </button>\n }\n </div>\n <div class=\"custom-color-input\">\n <label for=\"customColor\">Custom:</label>\n <input\n id=\"customColor\"\n type=\"color\"\n [(ngModel)]=\"formData.color\"\n class=\"custom-color-picker\" />\n <span class=\"color-value\">{{ formData.color }}</span>\n </div>\n </div>\n </div>\n\n <!-- Icon Selector -->\n <div class=\"form-field\">\n <label>Icon</label>\n <div class=\"icon-grid\">\n @for (icon of availableIcons; track icon) {\n <button\n type=\"button\"\n class=\"icon-option\"\n [class.selected]=\"formData.icon === icon\"\n [style.color]=\"formData.icon === icon ? formData.color : null\"\n (click)=\"selectIcon(icon)\"\n [title]=\"icon\">\n <i class=\"fa-solid {{ icon }}\"></i>\n </button>\n }\n </div>\n </div>\n </div>\n\n <mj-dialog-actions>\n <button mjButton variant=\"primary\" (click)=\"onSave()\">\n {{ isEditMode ? 'Save Changes' : 'Create Folder' }}\n </button>\n <button mjButton (click)=\"onCancel()\">Cancel</button>\n </mj-dialog-actions>\n </mj-dialog>\n `,\n styles: [`\n .project-form {\n padding: 20px 24px 8px;\n display: flex;\n flex-direction: column;\n gap: 22px;\n }\n\n /* Live preview chip */\n .folder-preview {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n }\n .folder-preview-chip {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n transition: background-color 150ms ease, color 150ms ease;\n }\n .folder-preview-name {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .form-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .form-field label {\n font-weight: 600;\n font-size: 13px;\n letter-spacing: 0.01em;\n color: var(--mj-text-secondary);\n }\n\n .form-field label.required::after {\n content: '*';\n color: var(--mj-status-error);\n margin-left: 4px;\n }\n\n .full-width { width: 100%; }\n\n .error-message {\n color: var(--mj-status-error);\n font-size: 12px;\n }\n\n /* Color Picker */\n .color-picker-section {\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 14px;\n background: var(--mj-bg-surface);\n }\n\n .color-palette {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .color-swatch {\n width: 100%;\n aspect-ratio: 1;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n padding: 0;\n transition: transform 120ms ease, box-shadow 120ms ease;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n }\n\n .color-swatch:hover {\n transform: scale(1.12);\n }\n\n .color-swatch.selected {\n box-shadow: 0 0 0 2px var(--mj-bg-surface), 0 0 0 4px var(--mj-brand-primary);\n }\n\n .custom-color-input {\n display: flex;\n align-items: center;\n gap: 10px;\n padding-top: 14px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n\n .custom-color-input label {\n margin: 0;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n }\n\n .custom-color-picker {\n width: 44px;\n height: 30px;\n padding: 2px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n cursor: pointer;\n background: var(--mj-bg-surface);\n }\n\n .color-value {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 13px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n }\n\n /* Icon Selector */\n .icon-grid {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 8px;\n max-height: 184px;\n overflow-y: auto;\n padding: 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n }\n\n .icon-option {\n aspect-ratio: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;\n }\n\n .icon-option:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n transform: translateY(-1px);\n }\n\n .icon-option.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 1px var(--mj-brand-primary);\n }\n\n .icon-option i { font-size: 17px; }\n\n /* Scrollbar */\n .icon-grid::-webkit-scrollbar { width: 8px; }\n .icon-grid::-webkit-scrollbar-track {\n background: transparent;\n }\n .icon-grid::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 4px;\n }\n .icon-grid::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n }\n `]\n})\nexport class ProjectFormModalComponent extends BaseAngularComponent implements OnInit {\n @Input() dialogRef!: MJDialogRef;\n @Input() project: MJProjectEntity | null = null;\n @Input() environmentId!: string;\n @Input() currentUser!: UserInfo;\n /** When creating a new folder, the parent folder ID for nesting (null = top level). */\n @Input() parentId: string | null = null;\n\n @Output() projectSaved = new EventEmitter<MJProjectEntity>();\n\n public formData: ProjectFormData = {\n name: '',\n description: '',\n color: '#0076B6',\n icon: 'fa-folder'\n };\n\n public showNameError = false;\n public isEditMode = false;\n public availableColors = DEFAULT_PROJECT_COLORS;\n public availableIcons = DEFAULT_PROJECT_ICONS;\n\n /** Translucent tint of the selected color, used behind the preview/icon glyph. */\n public get chipBackground(): string {\n const hex = this.formData.color || '#0076B6';\n // 8-digit hex (#RRGGBBAA) — ~14% alpha tint of the chosen color\n return /^#[0-9a-fA-F]{6}$/.test(hex) ? `${hex}24` : hex;\n }\n\n constructor(private cdr: ChangeDetectorRef) {\n super();}\n\n ngOnInit(): void {\n this.isEditMode = this.project != null;\n\n if (this.project) {\n this.loadProjectData();\n }\n }\n\n private loadProjectData(): void {\n if (!this.project) return;\n\n this.formData = {\n name: this.project.Name || '',\n description: this.project.Description || '',\n color: this.project.Color || '#0076B6',\n icon: this.project.Icon || 'fa-folder'\n };\n }\n\n selectColor(color: string): void {\n this.formData.color = color;\n this.cdr.detectChanges();\n }\n\n selectIcon(icon: string): void {\n this.formData.icon = icon;\n this.cdr.detectChanges();\n }\n\n async onSave(): Promise<void> {\n // Validate\n if (!this.formData.name.trim()) {\n this.showNameError = true;\n this.cdr.detectChanges();\n return;\n }\n\n this.showNameError = false;\n\n try {\n const md = this.ProviderToUse;\n const project = this.project || await md.GetEntityObject<MJProjectEntity>('MJ: Projects', this.currentUser);\n\n project.Name = this.formData.name.trim();\n project.Description = this.formData.description.trim() || null;\n project.Color = this.formData.color;\n project.Icon = this.formData.icon;\n\n if (!this.isEditMode) {\n project.EnvironmentID = this.environmentId;\n project.IsArchived = false;\n if (this.parentId) {\n project.ParentID = this.parentId;\n }\n }\n\n const saved = await project.Save();\n if (saved) {\n this.projectSaved.emit(project);\n this.dialogRef.Close();\n } else {\n throw new Error('Failed to save project');\n }\n } catch (error) {\n console.error('Error saving project:', error);\n alert('Failed to save project. Please try again.');\n }\n }\n\n onCancel(): void {\n this.dialogRef.Close();\n }\n}\n"]}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import type { Type } from '@angular/core';
|
|
2
|
+
import { JSONValue, RealtimeToolDefinition } from '@memberjunction/ai';
|
|
3
|
+
/**
|
|
4
|
+
* Host services handed to a {@link BaseRealtimeChannelClient} at {@link BaseRealtimeChannelClient.Initialize}.
|
|
5
|
+
*
|
|
6
|
+
* The context is the plugin's ONLY line back to the live session — channels never talk to
|
|
7
|
+
* `RealtimeSessionService` (or any host component) directly, which is what keeps them drop-in
|
|
8
|
+
* plugins. Every member is host-implemented:
|
|
9
|
+
*
|
|
10
|
+
* - the SESSION SERVICE supplies {@link SendContextNote} (perception feed into the live
|
|
11
|
+
* model), {@link RequestSave} (debounced state-of-record persistence onto the session's
|
|
12
|
+
* `MJ: AI Agent Session Channels` row) and {@link AgentName};
|
|
13
|
+
* - the OVERLAY SHELL wires {@link SetFocusMode} (through the service's focus stream) so a
|
|
14
|
+
* channel surface can request the focus layout — main call column collapsed, surface
|
|
15
|
+
* panel filling the overlay, floating call pill riding on top.
|
|
16
|
+
*/
|
|
17
|
+
export interface RealtimeChannelContext {
|
|
18
|
+
/** Display name of the agent the live session fronts (e.g. `"Sage"`), fixed at session start. */
|
|
19
|
+
AgentName: string;
|
|
20
|
+
/**
|
|
21
|
+
* Feeds a background context note into the live realtime model (no spoken reply is
|
|
22
|
+
* requested) — the PERCEPTION direction of the channel: serialized state deltas flow here
|
|
23
|
+
* so the agent stays aware of what's on the surface. No-op when the session isn't live.
|
|
24
|
+
*/
|
|
25
|
+
SendContextNote(text: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* Asks the host to persist `stateJson` as this channel's state of record. The host
|
|
28
|
+
* DEBOUNCES (a change burst becomes one save) and flushes any pending save at session
|
|
29
|
+
* teardown — the plugin just calls this on every state mutation and never schedules
|
|
30
|
+
* timers itself. Best-effort: persistence failures are logged host-side, never thrown.
|
|
31
|
+
*/
|
|
32
|
+
RequestSave(stateJson: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Requests (or releases) the FOCUS layout for this channel's surface: the overlay
|
|
35
|
+
* collapses the main call column so the surface owns the screen, with a compact floating
|
|
36
|
+
* call pill keeping mute / thread / end reachable. Any channel may request it; the host
|
|
37
|
+
* tracks which channel holds focus and routes the pill's "exit" back to it via
|
|
38
|
+
* {@link BaseRealtimeChannelClient.RequestFocusExit}.
|
|
39
|
+
*/
|
|
40
|
+
SetFocusMode(on: boolean): void;
|
|
41
|
+
/**
|
|
42
|
+
* Asks the live model to SPEAK a response to the supplied instructions RIGHT NOW —
|
|
43
|
+
* the channel's "react to this" path, e.g. a widget submission the user expects an
|
|
44
|
+
* audible reaction to ({@link SendContextNote} deliberately never triggers speech).
|
|
45
|
+
* Rides the realtime client's spoken-update channel, so on some providers the spoken
|
|
46
|
+
* reply is narration-kind (ephemeral, not persisted as a caption). OPTIONAL member:
|
|
47
|
+
* older host contexts may not supply it — plugins must call it null-safely.
|
|
48
|
+
*/
|
|
49
|
+
RequestSpokenResponse?(instructions: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* Persists a snapshot of the channel's state as a first-class versioned artifact
|
|
52
|
+
* (`MJ: Artifacts` + version, linked into conversation history when possible) — e.g. the
|
|
53
|
+
* whiteboard's "Save to artifacts". Distinct from {@link RealtimeChannelContext.RequestSave},
|
|
54
|
+
* which maintains the session's rolling state of record. Best-effort: resolves to the
|
|
55
|
+
* created Artifact ID, or `null` on failure (logged host-side, never thrown). Works during
|
|
56
|
+
* the call AND right after it ends (the host retains the session id for late saves).
|
|
57
|
+
*/
|
|
58
|
+
SaveAsArtifact(name: string, contentJson: string): Promise<string | null>;
|
|
59
|
+
/**
|
|
60
|
+
* The live `MJ: AI Agent Sessions` id this channel belongs to, or `null` before the
|
|
61
|
+
* session has minted / after it has torn down. A channel whose tools or surface drive a
|
|
62
|
+
* SERVER-SIDE resource (e.g. the Remote Browser channel's server-hosted browser) passes
|
|
63
|
+
* this as the `agentSessionID` argument to its own GraphQL resolvers via
|
|
64
|
+
* {@link ExecuteServerAction}. Most channels (whiteboard, shared doc) keep all state
|
|
65
|
+
* client-side and never read it.
|
|
66
|
+
*/
|
|
67
|
+
AgentSessionID: string | null;
|
|
68
|
+
/**
|
|
69
|
+
* Executes a CHANNEL-SPECIFIC GraphQL operation against the session's MJ server — the
|
|
70
|
+
* escape hatch for channels backed by a SERVER-SIDE resource that the generic
|
|
71
|
+
* {@link RequestSave} / {@link SaveAsArtifact} contract doesn't cover (e.g. the Remote
|
|
72
|
+
* Browser channel driving a server-hosted browser through its own
|
|
73
|
+
* `ExecuteRemoteBrowserAction` mutation + `RemoteBrowserSnapshot` query).
|
|
74
|
+
*
|
|
75
|
+
* The host runs the operation through the SAME provider the live session uses, so the
|
|
76
|
+
* request rides the authenticated session. Best-effort and tolerant: a transport or
|
|
77
|
+
* server error resolves to `null` (logged host-side) rather than throwing, so a channel
|
|
78
|
+
* can map the failure to a model-readable result string without `try/catch`.
|
|
79
|
+
*
|
|
80
|
+
* @typeParam TResult The expected shape of the GraphQL operation's data payload.
|
|
81
|
+
* @param query The GraphQL query/mutation document.
|
|
82
|
+
* @param variables The operation variables (all JSON-serializable).
|
|
83
|
+
* @returns The operation's `data` payload, or `null` on any failure / when no session is live.
|
|
84
|
+
*/
|
|
85
|
+
ExecuteServerAction<TResult>(query: string, variables: Record<string, JSONValue>): Promise<TResult | null>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The first-run INTRO content for an interactive channel — the concise "what is this surface
|
|
89
|
+
* and how do I use it" copy the overlay shows the very first time a user opens this channel's
|
|
90
|
+
* tab (persisted "seen" per user, so it's shown ONCE per channel per user).
|
|
91
|
+
*
|
|
92
|
+
* A channel opts in by overriding {@link BaseRealtimeChannelClient.GetOnboardingDetails}; the
|
|
93
|
+
* default returns `null`, so the base Voice/text channel (which has no plugin at all) AND any
|
|
94
|
+
* plugin that doesn't override it show nothing.
|
|
95
|
+
*/
|
|
96
|
+
export interface ChannelOnboardingDetails {
|
|
97
|
+
/** Short title, usually the surface name (e.g. `"Whiteboard"`). */
|
|
98
|
+
Heading: string;
|
|
99
|
+
/** One or two sentences: what the surface is and what the user can expect to see on it. */
|
|
100
|
+
Description: string;
|
|
101
|
+
/** Optional quick-tip bullets (kept to 2-3 short, scannable lines). */
|
|
102
|
+
Tips?: string[];
|
|
103
|
+
/** Optional Font Awesome icon class for the intro panel (e.g. `'fa-solid fa-chalkboard'`). */
|
|
104
|
+
IconClass?: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Base class for CLIENT-SIDE interactive-channel plugins (per
|
|
108
|
+
* `plans/ai-agent-sessions.md` → "Interactive Channels" / "Pluggable Channel Interfaces").
|
|
109
|
+
*
|
|
110
|
+
* An interactive channel is a bidirectional surface the session's single realtime agent
|
|
111
|
+
* both PERCEIVES and ACTS UPON (whiteboard, shared doc, map, …). A concrete plugin
|
|
112
|
+
* contributes everything the channel needs, so the session service / call overlay carry
|
|
113
|
+
* ZERO channel-specific wiring:
|
|
114
|
+
*
|
|
115
|
+
* 1. a CLIENT-EXECUTED TOOL SET ({@link GetToolDefinitions}, declared to the realtime
|
|
116
|
+
* model at session mint) plus the local executor ({@link ApplyAgentTool}) the host
|
|
117
|
+
* routes `{@link ToolNamePrefix}*` calls to — the ACTION direction;
|
|
118
|
+
* 2. a STATE→CONTEXT SERIALIZER policy — the plugin owns its state engine and pushes
|
|
119
|
+
* coalesced deltas through {@link RealtimeChannelContext.SendContextNote} — the
|
|
120
|
+
* PERCEPTION direction;
|
|
121
|
+
* 3. an OPTIONAL ANGULAR SURFACE ({@link GetSurfaceComponent}) the overlay creates dynamically
|
|
122
|
+
* in a channel tab, handed back through {@link BindSurface} so the plugin wires its own
|
|
123
|
+
* inputs/outputs (the host never knows the component's API). A channel may be **server-only**
|
|
124
|
+
* (no rendered surface) — e.g. a bridge-contributed meeting-controls or native-whiteboard
|
|
125
|
+
* channel whose surface lives on the external platform, not in MJ. Such a channel returns
|
|
126
|
+
* `null` from {@link GetSurfaceComponent} ({@link HasSurface} is `false`) and the overlay
|
|
127
|
+
* simply skips its tab while still wiring its tools + perception;
|
|
128
|
+
* 4. a STATE OF RECORD ({@link SerializeState}, persisted via
|
|
129
|
+
* {@link RealtimeChannelContext.RequestSave} under {@link ChannelName}).
|
|
130
|
+
*
|
|
131
|
+
* ### Registration & resolution (mirrors the realtime model drivers)
|
|
132
|
+
* Concrete plugins are `@RegisterClass(BaseRealtimeChannelClient, '<ClientPluginClass>')`
|
|
133
|
+
* and are resolved at session start from the `MJ: AI Agent Channels` registry: each ACTIVE
|
|
134
|
+
* row's `ClientPluginClass` is the ClassFactory key (exactly how `BaseRealtimeClient`
|
|
135
|
+
* drivers resolve by provider key). Ship a `Load<YourChannel>()` no-op alongside the class
|
|
136
|
+
* and call it from a static code path to defeat tree-shaking.
|
|
137
|
+
*
|
|
138
|
+
* ### Lifecycle — ONE INSTANCE PER SESSION (not a singleton)
|
|
139
|
+
* `ClassFactory.CreateInstance` → {@link Initialize}(ctx) → zero or more
|
|
140
|
+
* {@link BindSurface}/{@link UnbindSurface} cycles (the surface pane is created/destroyed
|
|
141
|
+
* with the overlay's tab panel, e.g. collapse/expand) → {@link Dispose} at teardown.
|
|
142
|
+
* {@link ApplyAgentTool} MUST work with NO surface bound (apply to the state engine
|
|
143
|
+
* directly; skip the UI garnish) — tool calls can arrive while the panel is collapsed.
|
|
144
|
+
*
|
|
145
|
+
* @typeParam TSurface The plugin's Angular surface component type. The host only ever
|
|
146
|
+
* sees the default (`object`) — the typed parameter exists so concrete plugins get a
|
|
147
|
+
* fully typed {@link BindSurface} without casts.
|
|
148
|
+
*/
|
|
149
|
+
export declare abstract class BaseRealtimeChannelClient<TSurface extends object = object> {
|
|
150
|
+
/**
|
|
151
|
+
* The host context, available from {@link Initialize} until {@link Dispose}.
|
|
152
|
+
* `null` outside that window — guard with `?.` in any code that can run early/late.
|
|
153
|
+
*/
|
|
154
|
+
protected Context: RealtimeChannelContext | null;
|
|
155
|
+
/**
|
|
156
|
+
* The channel definition name — MUST match the `MJ: AI Agent Channels` row's `Name`
|
|
157
|
+
* (e.g. `'Whiteboard'`). Used as the persistence key for {@link SerializeState} saves
|
|
158
|
+
* and as the channel tab's stable key.
|
|
159
|
+
*/
|
|
160
|
+
abstract get ChannelName(): string;
|
|
161
|
+
/**
|
|
162
|
+
* The shared name prefix of every tool this channel exposes (e.g. `'Whiteboard_'`).
|
|
163
|
+
* The host registers ONE local-execution route per plugin: tool calls whose name starts
|
|
164
|
+
* with this prefix go to {@link ApplyAgentTool} instead of the server relay.
|
|
165
|
+
*/
|
|
166
|
+
abstract get ToolNamePrefix(): string;
|
|
167
|
+
/** Label for the channel's tab on the overlay's surface panel (e.g. `'Whiteboard'`). */
|
|
168
|
+
abstract get TabTitle(): string;
|
|
169
|
+
/** Font Awesome icon class for the channel's tab (e.g. `'fa-solid fa-chalkboard'`). */
|
|
170
|
+
abstract get TabIcon(): string;
|
|
171
|
+
/**
|
|
172
|
+
* The channel's CLIENT-EXECUTED tool declarations, aggregated by the session service
|
|
173
|
+
* into the `clientTools` set declared to the realtime model at session mint. The server
|
|
174
|
+
* only DECLARES these — execution stays in the browser via {@link ApplyAgentTool}.
|
|
175
|
+
*/
|
|
176
|
+
abstract GetToolDefinitions(): RealtimeToolDefinition[];
|
|
177
|
+
/**
|
|
178
|
+
* Executes ONE agent tool call locally (the ACTION direction) and returns the result
|
|
179
|
+
* JSON string fed back to the model as the `tool_response`. Called for every tool whose
|
|
180
|
+
* name starts with {@link ToolNamePrefix}. Must work both WITH a bound surface (apply +
|
|
181
|
+
* UI garnish) and WITHOUT one (apply to the state engine directly — the tab pane may not
|
|
182
|
+
* exist, e.g. the surface panel is collapsed). Should not throw: return a
|
|
183
|
+
* `{ success: false, error }` payload so the model can narrate the failure (the host
|
|
184
|
+
* additionally wraps anything thrown).
|
|
185
|
+
*/
|
|
186
|
+
abstract ApplyAgentTool(toolName: string, argsJson: string): string | Promise<string>;
|
|
187
|
+
/**
|
|
188
|
+
* The Angular component the overlay creates dynamically as this channel's tab pane, or `null`
|
|
189
|
+
* for a **server-only** channel that renders no MJ surface (its surface, if any, lives on the
|
|
190
|
+
* external platform — e.g. a bridge-contributed native whiteboard or meeting-controls channel).
|
|
191
|
+
*
|
|
192
|
+
* When this returns `null`, the overlay renders NO tab for the channel and never calls
|
|
193
|
+
* {@link BindSurface}/{@link UnbindSurface} — but the channel's tools ({@link GetToolDefinitions} /
|
|
194
|
+
* {@link ApplyAgentTool}) and perception ({@link RealtimeChannelContext.SendContextNote}) still run.
|
|
195
|
+
* A created surface instance is handed straight back via {@link BindSurface}; the host treats it as
|
|
196
|
+
* opaque.
|
|
197
|
+
*
|
|
198
|
+
* Default: `null` (server-only). A channel with a rendered surface overrides this to return its
|
|
199
|
+
* component type.
|
|
200
|
+
*/
|
|
201
|
+
GetSurfaceComponent(): Type<TSurface> | null;
|
|
202
|
+
/**
|
|
203
|
+
* Whether this channel has a rendered MJ surface ({@link GetSurfaceComponent} returns non-null).
|
|
204
|
+
* The overlay uses this to decide whether to register a surface tab; server-only channels are
|
|
205
|
+
* `false`. Override only if surface availability must be decided WITHOUT constructing the type
|
|
206
|
+
* (the default calls {@link GetSurfaceComponent} once).
|
|
207
|
+
*/
|
|
208
|
+
HasSurface(): boolean;
|
|
209
|
+
/**
|
|
210
|
+
* The channel's FIRST-RUN INTRO content, or `null` when the channel offers no onboarding.
|
|
211
|
+
* The overlay shows this once per channel per user — the first time the user opens this
|
|
212
|
+
* channel's surface tab — and remembers "seen" via the user's settings (NOT localStorage),
|
|
213
|
+
* so it never re-appears on later sessions or other devices.
|
|
214
|
+
*
|
|
215
|
+
* Default: `null` (no intro). The base Voice/text channel has no plugin at all, so it never
|
|
216
|
+
* shows an intro; an interactive channel with a surface worth explaining (whiteboard, remote
|
|
217
|
+
* browser, …) overrides this to return its {@link ChannelOnboardingDetails}. A plugin that
|
|
218
|
+
* doesn't override it simply shows nothing — onboarding is strictly opt-in.
|
|
219
|
+
*/
|
|
220
|
+
GetOnboardingDetails(): ChannelOnboardingDetails | null;
|
|
221
|
+
/**
|
|
222
|
+
* Called by the host right after it created the surface component (and BEFORE the
|
|
223
|
+
* component's first change detection, so inputs set here are visible in its `ngOnInit`).
|
|
224
|
+
* The plugin — which knows its own component type — sets inputs (state engine, agent
|
|
225
|
+
* name, …) and subscribes outputs here, wiring perception/garnish flows back through
|
|
226
|
+
* {@link Context}. May be called again with a NEW instance after an
|
|
227
|
+
* {@link UnbindSurface} (the pane is destroyed/recreated with the tab panel).
|
|
228
|
+
*/
|
|
229
|
+
abstract BindSurface(instance: TSurface): void;
|
|
230
|
+
/**
|
|
231
|
+
* Called by the host when the surface component is being destroyed (tab panel
|
|
232
|
+
* collapsed / overlay torn down). Drop the instance reference and unsubscribe any
|
|
233
|
+
* output subscriptions — after this, {@link ApplyAgentTool} runs in its no-surface
|
|
234
|
+
* mode. Default: no-op.
|
|
235
|
+
*/
|
|
236
|
+
UnbindSurface(): void;
|
|
237
|
+
/**
|
|
238
|
+
* Binds the host context and invokes the {@link OnInitialize} hook. Called exactly once
|
|
239
|
+
* per session, right after ClassFactory instantiation and before any tool call or
|
|
240
|
+
* surface bind.
|
|
241
|
+
*/
|
|
242
|
+
Initialize(ctx: RealtimeChannelContext): void;
|
|
243
|
+
/**
|
|
244
|
+
* Subclass hook invoked from {@link Initialize} once {@link Context} is bound — wire
|
|
245
|
+
* state-engine subscriptions (e.g. state change → `Context.RequestSave(...)`) here.
|
|
246
|
+
* Default: no-op.
|
|
247
|
+
*/
|
|
248
|
+
protected OnInitialize(): void;
|
|
249
|
+
/**
|
|
250
|
+
* Max time {@link ResolveAgentSessionId} waits for the session id to bind before giving up, and the
|
|
251
|
+
* poll interval it re-checks on. Protected so tests can shrink the wait; production keeps the
|
|
252
|
+
* defaults (the real mint race is sub-second, 8s is generous headroom).
|
|
253
|
+
*/
|
|
254
|
+
protected SessionIdWaitTimeoutMs: number;
|
|
255
|
+
protected SessionIdWaitIntervalMs: number;
|
|
256
|
+
/**
|
|
257
|
+
* Resolves the live {@link RealtimeChannelContext.AgentSessionID}, briefly WAITING for it when it
|
|
258
|
+
* isn't bound yet rather than giving up instantly. `AgentSessionID` is a live getter over the
|
|
259
|
+
* session service's current id: it reads `null` in the window BEFORE the session mints (the
|
|
260
|
+
* realtime model can fire a tool call the very first beat it connects, before `mintSession`
|
|
261
|
+
* resolves) and again AFTER teardown. Server-backed tool paths (e.g. the Remote Browser channel's
|
|
262
|
+
* `browser_*` tools) call this instead of reading `Context?.AgentSessionID` synchronously, so a tool
|
|
263
|
+
* invoked a beat early WAITS for the session to come live — defense-in-depth against the
|
|
264
|
+
* "session id missing" race — instead of returning a hard failure to the model.
|
|
265
|
+
*
|
|
266
|
+
* Returns the id as soon as it's non-null (the common path resolves immediately, no delay), or
|
|
267
|
+
* `null` if it's still unbound after {@link SessionIdWaitTimeoutMs} — or the channel was
|
|
268
|
+
* {@link Dispose}d in the meantime (`Context` goes null, so we stop waiting on a torn-down session).
|
|
269
|
+
*/
|
|
270
|
+
protected ResolveAgentSessionId(): Promise<string | null>;
|
|
271
|
+
/**
|
|
272
|
+
* Serializes the channel's current state of record (the payload persisted on the
|
|
273
|
+
* session's channel row), or `null` when the channel keeps no persistent state.
|
|
274
|
+
* Default: `null`.
|
|
275
|
+
*/
|
|
276
|
+
SerializeState(): string | null;
|
|
277
|
+
/**
|
|
278
|
+
* Restores a PRIOR session's saved channel state (the payload a previous session
|
|
279
|
+
* persisted via {@link SerializeState} / {@link RealtimeChannelContext.RequestSave}).
|
|
280
|
+
* Invoked by the session host AFTER {@link Initialize} and BEFORE any surface binding,
|
|
281
|
+
* when a prior session's saved state exists for this channel.
|
|
282
|
+
*
|
|
283
|
+
* Returns `true` when the state was applied; `false` when the channel ignored it —
|
|
284
|
+
* either because it keeps no persistent state (this default) or because the payload was
|
|
285
|
+
* malformed/incompatible. Implementations MUST be tolerant: never throw on bad input,
|
|
286
|
+
* just return `false` and start fresh.
|
|
287
|
+
*/
|
|
288
|
+
RestoreState(stateJson: string): boolean;
|
|
289
|
+
/**
|
|
290
|
+
* The focus pill's "exit" affordance, routed by the overlay to the channel that holds
|
|
291
|
+
* focus. Implementations should leave focus mode through their OWN surface (so surface
|
|
292
|
+
* toggles stay in sync), ultimately emitting `Context.SetFocusMode(false)`. The overlay
|
|
293
|
+
* defensively clears its layout flag as well, so a no-op default is safe.
|
|
294
|
+
*/
|
|
295
|
+
RequestFocusExit(): void;
|
|
296
|
+
/**
|
|
297
|
+
* Tears the plugin down at session end: release the surface binding, unsubscribe
|
|
298
|
+
* state-engine subscriptions, then drop the context. Subclasses overriding this MUST
|
|
299
|
+
* call `super.Dispose()`. Any final state save has already been flushed by the host
|
|
300
|
+
* (the debounced {@link RealtimeChannelContext.RequestSave} pipeline) before disposal.
|
|
301
|
+
*/
|
|
302
|
+
Dispose(): void;
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=base-realtime-channel-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-realtime-channel-client.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/base-realtime-channel-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for CLIENT-SIDE interactive-channel plugins (per
|
|
3
|
+
* `plans/ai-agent-sessions.md` → "Interactive Channels" / "Pluggable Channel Interfaces").
|
|
4
|
+
*
|
|
5
|
+
* An interactive channel is a bidirectional surface the session's single realtime agent
|
|
6
|
+
* both PERCEIVES and ACTS UPON (whiteboard, shared doc, map, …). A concrete plugin
|
|
7
|
+
* contributes everything the channel needs, so the session service / call overlay carry
|
|
8
|
+
* ZERO channel-specific wiring:
|
|
9
|
+
*
|
|
10
|
+
* 1. a CLIENT-EXECUTED TOOL SET ({@link GetToolDefinitions}, declared to the realtime
|
|
11
|
+
* model at session mint) plus the local executor ({@link ApplyAgentTool}) the host
|
|
12
|
+
* routes `{@link ToolNamePrefix}*` calls to — the ACTION direction;
|
|
13
|
+
* 2. a STATE→CONTEXT SERIALIZER policy — the plugin owns its state engine and pushes
|
|
14
|
+
* coalesced deltas through {@link RealtimeChannelContext.SendContextNote} — the
|
|
15
|
+
* PERCEPTION direction;
|
|
16
|
+
* 3. an OPTIONAL ANGULAR SURFACE ({@link GetSurfaceComponent}) the overlay creates dynamically
|
|
17
|
+
* in a channel tab, handed back through {@link BindSurface} so the plugin wires its own
|
|
18
|
+
* inputs/outputs (the host never knows the component's API). A channel may be **server-only**
|
|
19
|
+
* (no rendered surface) — e.g. a bridge-contributed meeting-controls or native-whiteboard
|
|
20
|
+
* channel whose surface lives on the external platform, not in MJ. Such a channel returns
|
|
21
|
+
* `null` from {@link GetSurfaceComponent} ({@link HasSurface} is `false`) and the overlay
|
|
22
|
+
* simply skips its tab while still wiring its tools + perception;
|
|
23
|
+
* 4. a STATE OF RECORD ({@link SerializeState}, persisted via
|
|
24
|
+
* {@link RealtimeChannelContext.RequestSave} under {@link ChannelName}).
|
|
25
|
+
*
|
|
26
|
+
* ### Registration & resolution (mirrors the realtime model drivers)
|
|
27
|
+
* Concrete plugins are `@RegisterClass(BaseRealtimeChannelClient, '<ClientPluginClass>')`
|
|
28
|
+
* and are resolved at session start from the `MJ: AI Agent Channels` registry: each ACTIVE
|
|
29
|
+
* row's `ClientPluginClass` is the ClassFactory key (exactly how `BaseRealtimeClient`
|
|
30
|
+
* drivers resolve by provider key). Ship a `Load<YourChannel>()` no-op alongside the class
|
|
31
|
+
* and call it from a static code path to defeat tree-shaking.
|
|
32
|
+
*
|
|
33
|
+
* ### Lifecycle — ONE INSTANCE PER SESSION (not a singleton)
|
|
34
|
+
* `ClassFactory.CreateInstance` → {@link Initialize}(ctx) → zero or more
|
|
35
|
+
* {@link BindSurface}/{@link UnbindSurface} cycles (the surface pane is created/destroyed
|
|
36
|
+
* with the overlay's tab panel, e.g. collapse/expand) → {@link Dispose} at teardown.
|
|
37
|
+
* {@link ApplyAgentTool} MUST work with NO surface bound (apply to the state engine
|
|
38
|
+
* directly; skip the UI garnish) — tool calls can arrive while the panel is collapsed.
|
|
39
|
+
*
|
|
40
|
+
* @typeParam TSurface The plugin's Angular surface component type. The host only ever
|
|
41
|
+
* sees the default (`object`) — the typed parameter exists so concrete plugins get a
|
|
42
|
+
* fully typed {@link BindSurface} without casts.
|
|
43
|
+
*/
|
|
44
|
+
export class BaseRealtimeChannelClient {
|
|
45
|
+
/**
|
|
46
|
+
* The host context, available from {@link Initialize} until {@link Dispose}.
|
|
47
|
+
* `null` outside that window — guard with `?.` in any code that can run early/late.
|
|
48
|
+
*/
|
|
49
|
+
Context = null;
|
|
50
|
+
/**
|
|
51
|
+
* The Angular component the overlay creates dynamically as this channel's tab pane, or `null`
|
|
52
|
+
* for a **server-only** channel that renders no MJ surface (its surface, if any, lives on the
|
|
53
|
+
* external platform — e.g. a bridge-contributed native whiteboard or meeting-controls channel).
|
|
54
|
+
*
|
|
55
|
+
* When this returns `null`, the overlay renders NO tab for the channel and never calls
|
|
56
|
+
* {@link BindSurface}/{@link UnbindSurface} — but the channel's tools ({@link GetToolDefinitions} /
|
|
57
|
+
* {@link ApplyAgentTool}) and perception ({@link RealtimeChannelContext.SendContextNote}) still run.
|
|
58
|
+
* A created surface instance is handed straight back via {@link BindSurface}; the host treats it as
|
|
59
|
+
* opaque.
|
|
60
|
+
*
|
|
61
|
+
* Default: `null` (server-only). A channel with a rendered surface overrides this to return its
|
|
62
|
+
* component type.
|
|
63
|
+
*/
|
|
64
|
+
GetSurfaceComponent() {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Whether this channel has a rendered MJ surface ({@link GetSurfaceComponent} returns non-null).
|
|
69
|
+
* The overlay uses this to decide whether to register a surface tab; server-only channels are
|
|
70
|
+
* `false`. Override only if surface availability must be decided WITHOUT constructing the type
|
|
71
|
+
* (the default calls {@link GetSurfaceComponent} once).
|
|
72
|
+
*/
|
|
73
|
+
HasSurface() {
|
|
74
|
+
return this.GetSurfaceComponent() != null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The channel's FIRST-RUN INTRO content, or `null` when the channel offers no onboarding.
|
|
78
|
+
* The overlay shows this once per channel per user — the first time the user opens this
|
|
79
|
+
* channel's surface tab — and remembers "seen" via the user's settings (NOT localStorage),
|
|
80
|
+
* so it never re-appears on later sessions or other devices.
|
|
81
|
+
*
|
|
82
|
+
* Default: `null` (no intro). The base Voice/text channel has no plugin at all, so it never
|
|
83
|
+
* shows an intro; an interactive channel with a surface worth explaining (whiteboard, remote
|
|
84
|
+
* browser, …) overrides this to return its {@link ChannelOnboardingDetails}. A plugin that
|
|
85
|
+
* doesn't override it simply shows nothing — onboarding is strictly opt-in.
|
|
86
|
+
*/
|
|
87
|
+
GetOnboardingDetails() {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Called by the host when the surface component is being destroyed (tab panel
|
|
92
|
+
* collapsed / overlay torn down). Drop the instance reference and unsubscribe any
|
|
93
|
+
* output subscriptions — after this, {@link ApplyAgentTool} runs in its no-surface
|
|
94
|
+
* mode. Default: no-op.
|
|
95
|
+
*/
|
|
96
|
+
UnbindSurface() {
|
|
97
|
+
// default: nothing to release
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Binds the host context and invokes the {@link OnInitialize} hook. Called exactly once
|
|
101
|
+
* per session, right after ClassFactory instantiation and before any tool call or
|
|
102
|
+
* surface bind.
|
|
103
|
+
*/
|
|
104
|
+
Initialize(ctx) {
|
|
105
|
+
this.Context = ctx;
|
|
106
|
+
this.OnInitialize();
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Subclass hook invoked from {@link Initialize} once {@link Context} is bound — wire
|
|
110
|
+
* state-engine subscriptions (e.g. state change → `Context.RequestSave(...)`) here.
|
|
111
|
+
* Default: no-op.
|
|
112
|
+
*/
|
|
113
|
+
OnInitialize() {
|
|
114
|
+
// default: nothing to initialize
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Max time {@link ResolveAgentSessionId} waits for the session id to bind before giving up, and the
|
|
118
|
+
* poll interval it re-checks on. Protected so tests can shrink the wait; production keeps the
|
|
119
|
+
* defaults (the real mint race is sub-second, 8s is generous headroom).
|
|
120
|
+
*/
|
|
121
|
+
SessionIdWaitTimeoutMs = 8000;
|
|
122
|
+
SessionIdWaitIntervalMs = 200;
|
|
123
|
+
/**
|
|
124
|
+
* Resolves the live {@link RealtimeChannelContext.AgentSessionID}, briefly WAITING for it when it
|
|
125
|
+
* isn't bound yet rather than giving up instantly. `AgentSessionID` is a live getter over the
|
|
126
|
+
* session service's current id: it reads `null` in the window BEFORE the session mints (the
|
|
127
|
+
* realtime model can fire a tool call the very first beat it connects, before `mintSession`
|
|
128
|
+
* resolves) and again AFTER teardown. Server-backed tool paths (e.g. the Remote Browser channel's
|
|
129
|
+
* `browser_*` tools) call this instead of reading `Context?.AgentSessionID` synchronously, so a tool
|
|
130
|
+
* invoked a beat early WAITS for the session to come live — defense-in-depth against the
|
|
131
|
+
* "session id missing" race — instead of returning a hard failure to the model.
|
|
132
|
+
*
|
|
133
|
+
* Returns the id as soon as it's non-null (the common path resolves immediately, no delay), or
|
|
134
|
+
* `null` if it's still unbound after {@link SessionIdWaitTimeoutMs} — or the channel was
|
|
135
|
+
* {@link Dispose}d in the meantime (`Context` goes null, so we stop waiting on a torn-down session).
|
|
136
|
+
*/
|
|
137
|
+
async ResolveAgentSessionId() {
|
|
138
|
+
const immediate = this.Context?.AgentSessionID ?? null;
|
|
139
|
+
if (immediate) {
|
|
140
|
+
return immediate;
|
|
141
|
+
}
|
|
142
|
+
const intervalMs = Math.max(1, this.SessionIdWaitIntervalMs);
|
|
143
|
+
for (let waited = 0; waited < this.SessionIdWaitTimeoutMs; waited += intervalMs) {
|
|
144
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
145
|
+
// Context goes null on Dispose() — the session is gone, stop waiting.
|
|
146
|
+
if (!this.Context) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
const id = this.Context.AgentSessionID;
|
|
150
|
+
if (id) {
|
|
151
|
+
return id;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return this.Context?.AgentSessionID ?? null;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Serializes the channel's current state of record (the payload persisted on the
|
|
158
|
+
* session's channel row), or `null` when the channel keeps no persistent state.
|
|
159
|
+
* Default: `null`.
|
|
160
|
+
*/
|
|
161
|
+
SerializeState() {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Restores a PRIOR session's saved channel state (the payload a previous session
|
|
166
|
+
* persisted via {@link SerializeState} / {@link RealtimeChannelContext.RequestSave}).
|
|
167
|
+
* Invoked by the session host AFTER {@link Initialize} and BEFORE any surface binding,
|
|
168
|
+
* when a prior session's saved state exists for this channel.
|
|
169
|
+
*
|
|
170
|
+
* Returns `true` when the state was applied; `false` when the channel ignored it —
|
|
171
|
+
* either because it keeps no persistent state (this default) or because the payload was
|
|
172
|
+
* malformed/incompatible. Implementations MUST be tolerant: never throw on bad input,
|
|
173
|
+
* just return `false` and start fresh.
|
|
174
|
+
*/
|
|
175
|
+
RestoreState(stateJson) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* The focus pill's "exit" affordance, routed by the overlay to the channel that holds
|
|
180
|
+
* focus. Implementations should leave focus mode through their OWN surface (so surface
|
|
181
|
+
* toggles stay in sync), ultimately emitting `Context.SetFocusMode(false)`. The overlay
|
|
182
|
+
* defensively clears its layout flag as well, so a no-op default is safe.
|
|
183
|
+
*/
|
|
184
|
+
RequestFocusExit() {
|
|
185
|
+
// default: the overlay's defensive clear handles it
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Tears the plugin down at session end: release the surface binding, unsubscribe
|
|
189
|
+
* state-engine subscriptions, then drop the context. Subclasses overriding this MUST
|
|
190
|
+
* call `super.Dispose()`. Any final state save has already been flushed by the host
|
|
191
|
+
* (the debounced {@link RealtimeChannelContext.RequestSave} pipeline) before disposal.
|
|
192
|
+
*/
|
|
193
|
+
Dispose() {
|
|
194
|
+
this.UnbindSurface();
|
|
195
|
+
this.Context = null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=base-realtime-channel-client.js.map
|