@memberjunction/ng-conversations 5.43.0 → 5.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts +0 -1
- package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts.map +1 -1
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js +56 -52
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js.map +1 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.d.ts +3 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.js +52 -52
- package/dist/lib/components/artifact/artifact-share-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-form-modal.component.js +10 -14
- package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-share-modal.component.d.ts +3 -1
- package/dist/lib/components/collection/collection-share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-share-modal.component.js +56 -56
- package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-tree.component.d.ts +3 -1
- package/dist/lib/components/collection/collection-tree.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-tree.component.js +10 -7
- package/dist/lib/components/collection/collection-tree.component.js.map +1 -1
- package/dist/lib/components/collection/collection-view.component.d.ts +3 -1
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-view.component.js +29 -41
- package/dist/lib/components/collection/collection-view.component.js.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.d.ts +4 -0
- package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.js +134 -166
- package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.d.ts +103 -0
- package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -0
- package/dist/lib/components/composer/ai-composer.component.js +263 -0
- package/dist/lib/components/composer/ai-composer.component.js.map +1 -0
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +76 -12
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +522 -158
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.d.ts +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.js.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.js +6 -9
- package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
- package/dist/lib/components/library/library-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/library/library-full-view.component.js +20 -24
- package/dist/lib/components/library/library-full-view.component.js.map +1 -1
- package/dist/lib/components/members/members-modal.component.d.ts.map +1 -1
- package/dist/lib/components/members/members-modal.component.js +10 -11
- package/dist/lib/components/members/members-modal.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +87 -23
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +245 -158
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +11 -3
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +73 -21
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.js +6 -9
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.d.ts +4 -1
- package/dist/lib/components/overlay/chat-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.js +9 -4
- package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +45 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +10 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +1 -1
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts +46 -0
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/channels/client-context-channel.js +174 -0
- package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.d.ts +123 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.js +397 -0
- package/dist/lib/components/realtime/evidence-playback/realtime-evidence-playback.component.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-state.d.ts +103 -0
- package/dist/lib/components/realtime/media/media-channel-state.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-state.js +143 -0
- package/dist/lib/components/realtime/media/media-channel-state.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-tools.d.ts +24 -0
- package/dist/lib/components/realtime/media/media-channel-tools.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/media-channel-tools.js +107 -0
- package/dist/lib/components/realtime/media/media-channel-tools.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts +89 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/media-channel.js +253 -0
- package/dist/lib/components/realtime/media/media-channel.js.map +1 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.d.ts +141 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.js +574 -0
- package/dist/lib/components/realtime/media/realtime-media-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +59 -14
- package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-activity-rail.component.js +277 -74
- package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +28 -27
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.js +144 -143
- package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +12 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.js +105 -43
- package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +2 -2
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.d.ts +41 -7
- package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.js +216 -102
- package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +0 -2
- package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-delegation-card.component.js +67 -71
- package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +364 -44
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +839 -153
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-state.d.ts +5 -5
- package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-state.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tab-style.d.ts +70 -0
- package/dist/lib/components/realtime/realtime-surface-tab-style.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tab-style.js +115 -0
- package/dist/lib/components/realtime/realtime-surface-tab-style.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +55 -57
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js +165 -143
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +80 -71
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js +83 -113
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.d.ts +270 -0
- package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-ui-config.js +212 -0
- package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -0
- package/dist/lib/components/search/search-panel.component.d.ts +2 -0
- package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
- package/dist/lib/components/search/search-panel.component.js +92 -101
- package/dist/lib/components/search/search-panel.component.js.map +1 -1
- package/dist/lib/components/share/share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/share/share-modal.component.js +10 -11
- package/dist/lib/components/share/share-modal.component.js.map +1 -1
- package/dist/lib/components/shared/user-picker.component.d.ts.map +1 -1
- package/dist/lib/components/shared/user-picker.component.js +12 -15
- package/dist/lib/components/shared/user-picker.component.js.map +1 -1
- package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts +11 -3
- package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts.map +1 -1
- package/dist/lib/components/sidebar/conversation-sidebar.component.js +34 -10
- package/dist/lib/components/sidebar/conversation-sidebar.component.js.map +1 -1
- package/dist/lib/components/sidebar/routines-section.component.d.ts +73 -0
- package/dist/lib/components/sidebar/routines-section.component.d.ts.map +1 -0
- package/dist/lib/components/sidebar/routines-section.component.js +211 -0
- package/dist/lib/components/sidebar/routines-section.component.js.map +1 -0
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +12 -0
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js +37 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +16 -5
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +51 -31
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/composer-plugins/agent-mention.provider.d.ts +16 -0
- package/dist/lib/composer-plugins/agent-mention.provider.d.ts.map +1 -0
- package/dist/lib/composer-plugins/agent-mention.provider.js +28 -0
- package/dist/lib/composer-plugins/agent-mention.provider.js.map +1 -0
- package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts +20 -0
- package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts.map +1 -0
- package/dist/lib/composer-plugins/base-conversation-mention.provider.js +32 -0
- package/dist/lib/composer-plugins/base-conversation-mention.provider.js.map +1 -0
- package/dist/lib/composer-plugins/load-composer-plugins.d.ts +9 -0
- package/dist/lib/composer-plugins/load-composer-plugins.d.ts.map +1 -0
- package/dist/lib/composer-plugins/load-composer-plugins.js +17 -0
- package/dist/lib/composer-plugins/load-composer-plugins.js.map +1 -0
- package/dist/lib/composer-plugins/record-mention.provider.d.ts +14 -0
- package/dist/lib/composer-plugins/record-mention.provider.d.ts.map +1 -0
- package/dist/lib/composer-plugins/record-mention.provider.js +26 -0
- package/dist/lib/composer-plugins/record-mention.provider.js.map +1 -0
- package/dist/lib/composer-plugins/skill-command.provider.d.ts +15 -0
- package/dist/lib/composer-plugins/skill-command.provider.d.ts.map +1 -0
- package/dist/lib/composer-plugins/skill-command.provider.js +27 -0
- package/dist/lib/composer-plugins/skill-command.provider.js.map +1 -0
- package/dist/lib/conversations.module.d.ts +68 -64
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +69 -18
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/models/conversation-state.model.d.ts +6 -3
- package/dist/lib/models/conversation-state.model.d.ts.map +1 -1
- package/dist/lib/models/conversation-state.model.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +9 -2
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +26 -2
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-attachment.service.d.ts +1 -1
- package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-attachment.service.js.map +1 -1
- package/dist/lib/services/mention-autocomplete.service.d.ts +42 -19
- package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
- package/dist/lib/services/mention-autocomplete.service.js +113 -18
- package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.d.ts +143 -0
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -0
- package/dist/lib/services/realtime-audio-recorder.js +379 -0
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -0
- package/dist/lib/services/realtime-pcm-wav.d.ts +75 -0
- package/dist/lib/services/realtime-pcm-wav.d.ts.map +1 -0
- package/dist/lib/services/realtime-pcm-wav.js +205 -0
- package/dist/lib/services/realtime-pcm-wav.js.map +1 -0
- package/dist/lib/services/realtime-session-review.service.d.ts +28 -1
- package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session-review.service.js +12 -3
- package/dist/lib/services/realtime-session-review.service.js.map +1 -1
- package/dist/lib/services/realtime-session.service.d.ts +210 -20
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +452 -21
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/realtime-sessions-adapter.js +1 -1
- package/dist/lib/services/realtime-sessions-adapter.js.map +1 -1
- package/dist/lib/services/ui-command-handler.service.d.ts +7 -2
- package/dist/lib/services/ui-command-handler.service.d.ts.map +1 -1
- package/dist/lib/services/ui-command-handler.service.js +6 -2
- package/dist/lib/services/ui-command-handler.service.js.map +1 -1
- package/dist/lib/utils/plan-mode-preference.d.ts +62 -0
- package/dist/lib/utils/plan-mode-preference.d.ts.map +1 -0
- package/dist/lib/utils/plan-mode-preference.js +130 -0
- package/dist/lib/utils/plan-mode-preference.js.map +1 -0
- package/dist/public-api.d.ts +29 -3
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +46 -3
- package/dist/public-api.js.map +1 -1
- package/package.json +30 -26
- package/dist/__tests__/attachment-badge.test.d.ts +0 -2
- package/dist/__tests__/attachment-badge.test.d.ts.map +0 -1
- package/dist/__tests__/attachment-badge.test.js +0 -66
- package/dist/__tests__/attachment-badge.test.js.map +0 -1
- package/dist/__tests__/channel-optional-surface.test.d.ts +0 -2
- package/dist/__tests__/channel-optional-surface.test.d.ts.map +0 -1
- package/dist/__tests__/channel-optional-surface.test.js +0 -53
- package/dist/__tests__/channel-optional-surface.test.js.map +0 -1
- package/dist/__tests__/chat-events.test.d.ts +0 -14
- package/dist/__tests__/chat-events.test.d.ts.map +0 -1
- package/dist/__tests__/chat-events.test.js +0 -109
- package/dist/__tests__/chat-events.test.js.map +0 -1
- package/dist/__tests__/collections-full-view.test.d.ts +0 -2
- package/dist/__tests__/collections-full-view.test.d.ts.map +0 -1
- package/dist/__tests__/collections-full-view.test.js +0 -225
- package/dist/__tests__/collections-full-view.test.js.map +0 -1
- package/dist/__tests__/conversation-cache.test.d.ts +0 -2
- package/dist/__tests__/conversation-cache.test.d.ts.map +0 -1
- package/dist/__tests__/conversation-cache.test.js +0 -233
- package/dist/__tests__/conversation-cache.test.js.map +0 -1
- package/dist/__tests__/conversation-naming.test.d.ts +0 -2
- package/dist/__tests__/conversation-naming.test.d.ts.map +0 -1
- package/dist/__tests__/conversation-naming.test.js +0 -110
- package/dist/__tests__/conversation-naming.test.js.map +0 -1
- package/dist/__tests__/delegation-result-parser.test.d.ts +0 -2
- package/dist/__tests__/delegation-result-parser.test.d.ts.map +0 -1
- package/dist/__tests__/delegation-result-parser.test.js +0 -107
- package/dist/__tests__/delegation-result-parser.test.js.map +0 -1
- package/dist/__tests__/distinct-artifacts.test.d.ts +0 -2
- package/dist/__tests__/distinct-artifacts.test.d.ts.map +0 -1
- package/dist/__tests__/distinct-artifacts.test.js +0 -56
- package/dist/__tests__/distinct-artifacts.test.js.map +0 -1
- package/dist/__tests__/event-wiring.test.d.ts +0 -15
- package/dist/__tests__/event-wiring.test.d.ts.map +0 -1
- package/dist/__tests__/event-wiring.test.js +0 -100
- package/dist/__tests__/event-wiring.test.js.map +0 -1
- package/dist/__tests__/index.test.d.ts +0 -2
- package/dist/__tests__/index.test.d.ts.map +0 -1
- package/dist/__tests__/index.test.js +0 -7
- package/dist/__tests__/index.test.js.map +0 -1
- package/dist/__tests__/narration-template.test.d.ts +0 -2
- package/dist/__tests__/narration-template.test.d.ts.map +0 -1
- package/dist/__tests__/narration-template.test.js +0 -76
- package/dist/__tests__/narration-template.test.js.map +0 -1
- package/dist/__tests__/notification-model.test.d.ts +0 -2
- package/dist/__tests__/notification-model.test.d.ts.map +0 -1
- package/dist/__tests__/notification-model.test.js +0 -68
- package/dist/__tests__/notification-model.test.js.map +0 -1
- package/dist/__tests__/realtime-agent-picker-models.test.d.ts +0 -2
- package/dist/__tests__/realtime-agent-picker-models.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-agent-picker-models.test.js +0 -49
- package/dist/__tests__/realtime-agent-picker-models.test.js.map +0 -1
- package/dist/__tests__/realtime-audio-visuals.test.d.ts +0 -2
- package/dist/__tests__/realtime-audio-visuals.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-audio-visuals.test.js +0 -123
- package/dist/__tests__/realtime-audio-visuals.test.js.map +0 -1
- package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts +0 -2
- package/dist/__tests__/realtime-delegation-card-cancel.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-delegation-card-cancel.test.js +0 -48
- package/dist/__tests__/realtime-delegation-card-cancel.test.js.map +0 -1
- package/dist/__tests__/realtime-disclosure.test.d.ts +0 -2
- package/dist/__tests__/realtime-disclosure.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-disclosure.test.js +0 -164
- package/dist/__tests__/realtime-disclosure.test.js.map +0 -1
- package/dist/__tests__/realtime-pairing.test.d.ts +0 -2
- package/dist/__tests__/realtime-pairing.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-pairing.test.js +0 -207
- package/dist/__tests__/realtime-pairing.test.js.map +0 -1
- package/dist/__tests__/realtime-review-lifecycle.test.d.ts +0 -2
- package/dist/__tests__/realtime-review-lifecycle.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-review-lifecycle.test.js +0 -154
- package/dist/__tests__/realtime-review-lifecycle.test.js.map +0 -1
- package/dist/__tests__/realtime-session-cancel-usage.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-cancel-usage.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-cancel-usage.test.js +0 -230
- package/dist/__tests__/realtime-session-cancel-usage.test.js.map +0 -1
- package/dist/__tests__/realtime-session-channels.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-channels.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-channels.test.js +0 -252
- package/dist/__tests__/realtime-session-channels.test.js.map +0 -1
- package/dist/__tests__/realtime-session-client-tools.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-client-tools.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-client-tools.test.js +0 -103
- package/dist/__tests__/realtime-session-client-tools.test.js.map +0 -1
- package/dist/__tests__/realtime-session-minimized.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-minimized.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-minimized.test.js +0 -32
- package/dist/__tests__/realtime-session-minimized.test.js.map +0 -1
- package/dist/__tests__/realtime-session-mint.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-mint.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-mint.test.js +0 -69
- package/dist/__tests__/realtime-session-mint.test.js.map +0 -1
- package/dist/__tests__/realtime-session-policy.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-policy.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-policy.test.js +0 -303
- package/dist/__tests__/realtime-session-policy.test.js.map +0 -1
- package/dist/__tests__/realtime-session-review.service.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-review.service.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-review.service.test.js +0 -743
- package/dist/__tests__/realtime-session-review.service.test.js.map +0 -1
- package/dist/__tests__/realtime-session-state.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-state.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-state.test.js +0 -83
- package/dist/__tests__/realtime-session-state.test.js.map +0 -1
- package/dist/__tests__/realtime-session-timeline-card.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-timeline-card.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-timeline-card.test.js +0 -106
- package/dist/__tests__/realtime-session-timeline-card.test.js.map +0 -1
- package/dist/__tests__/realtime-session-timeline.test.d.ts +0 -2
- package/dist/__tests__/realtime-session-timeline.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-session-timeline.test.js +0 -142
- package/dist/__tests__/realtime-session-timeline.test.js.map +0 -1
- package/dist/__tests__/realtime-sessions-adapter.test.d.ts +0 -19
- package/dist/__tests__/realtime-sessions-adapter.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-sessions-adapter.test.js +0 -188
- package/dist/__tests__/realtime-sessions-adapter.test.js.map +0 -1
- package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts +0 -2
- package/dist/__tests__/realtime-surface-panel-prefs.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-surface-panel-prefs.test.js +0 -100
- package/dist/__tests__/realtime-surface-panel-prefs.test.js.map +0 -1
- package/dist/__tests__/realtime-surface-tabs-model.test.d.ts +0 -2
- package/dist/__tests__/realtime-surface-tabs-model.test.d.ts.map +0 -1
- package/dist/__tests__/realtime-surface-tabs-model.test.js +0 -193
- package/dist/__tests__/realtime-surface-tabs-model.test.js.map +0 -1
- package/dist/__tests__/remote-browser-audio-player.test.d.ts +0 -2
- package/dist/__tests__/remote-browser-audio-player.test.d.ts.map +0 -1
- package/dist/__tests__/remote-browser-audio-player.test.js +0 -137
- package/dist/__tests__/remote-browser-audio-player.test.js.map +0 -1
- package/dist/__tests__/remote-browser-channel.test.d.ts +0 -2
- package/dist/__tests__/remote-browser-channel.test.d.ts.map +0 -1
- package/dist/__tests__/remote-browser-channel.test.js +0 -585
- package/dist/__tests__/remote-browser-channel.test.js.map +0 -1
- package/dist/__tests__/search-service.test.d.ts +0 -2
- package/dist/__tests__/search-service.test.d.ts.map +0 -1
- package/dist/__tests__/search-service.test.js +0 -114
- package/dist/__tests__/search-service.test.js.map +0 -1
- package/dist/__tests__/slot-defaults.test.d.ts +0 -24
- package/dist/__tests__/slot-defaults.test.d.ts.map +0 -1
- package/dist/__tests__/slot-defaults.test.js +0 -63
- package/dist/__tests__/slot-defaults.test.js.map +0 -1
- package/dist/__tests__/toast-service.test.d.ts +0 -2
- package/dist/__tests__/toast-service.test.d.ts.map +0 -1
- package/dist/__tests__/toast-service.test.js +0 -143
- package/dist/__tests__/toast-service.test.js.map +0 -1
- package/dist/__tests__/user-authorization.test.d.ts +0 -2
- package/dist/__tests__/user-authorization.test.d.ts.map +0 -1
- package/dist/__tests__/user-authorization.test.js +0 -97
- package/dist/__tests__/user-authorization.test.js.map +0 -1
- package/dist/__tests__/voice-session-narration.test.d.ts +0 -2
- package/dist/__tests__/voice-session-narration.test.d.ts.map +0 -1
- package/dist/__tests__/voice-session-narration.test.js +0 -609
- package/dist/__tests__/voice-session-narration.test.js.map +0 -1
- package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts +0 -2
- package/dist/__tests__/whiteboard-artifact-viewer.test.d.ts.map +0 -1
- package/dist/__tests__/whiteboard-artifact-viewer.test.js +0 -101
- package/dist/__tests__/whiteboard-artifact-viewer.test.js.map +0 -1
- package/dist/__tests__/whiteboard-channel.test.d.ts +0 -2
- package/dist/__tests__/whiteboard-channel.test.d.ts.map +0 -1
- package/dist/__tests__/whiteboard-channel.test.js +0 -260
- package/dist/__tests__/whiteboard-channel.test.js.map +0 -1
- package/dist/__tests__/whiteboard-restore-state.test.d.ts +0 -2
- package/dist/__tests__/whiteboard-restore-state.test.d.ts.map +0 -1
- package/dist/__tests__/whiteboard-restore-state.test.js +0 -108
- package/dist/__tests__/whiteboard-restore-state.test.js.map +0 -1
- package/dist/lib/components/mention/mention-dropdown.component.d.ts +0 -53
- package/dist/lib/components/mention/mention-dropdown.component.d.ts.map +0 -1
- package/dist/lib/components/mention/mention-dropdown.component.js +0 -276
- package/dist/lib/components/mention/mention-dropdown.component.js.map +0 -1
- package/dist/lib/components/mention/mention-editor.component.d.ts +0 -256
- package/dist/lib/components/mention/mention-editor.component.d.ts.map +0 -1
- package/dist/lib/components/mention/mention-editor.component.js +0 -1233
- package/dist/lib/components/mention/mention-editor.component.js.map +0 -1
- package/dist/lib/components/message/message-input-box.component.d.ts +0 -137
- package/dist/lib/components/message/message-input-box.component.d.ts.map +0 -1
- package/dist/lib/components/message/message-input-box.component.js +0 -321
- package/dist/lib/components/message/message-input-box.component.js.map +0 -1
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import { RealtimeSessionService } from '../lib/services/realtime-session.service';
|
|
3
|
-
function internals(service) {
|
|
4
|
-
return service;
|
|
5
|
-
}
|
|
6
|
-
function collectResults(service) {
|
|
7
|
-
const results = [];
|
|
8
|
-
service.DelegationResult$.subscribe(r => results.push(r));
|
|
9
|
-
return results;
|
|
10
|
-
}
|
|
11
|
-
describe('RealtimeSessionService — CancelDelegation (per-card ✕, explicit user intent)', () => {
|
|
12
|
-
let service;
|
|
13
|
-
let executeGQL;
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
service = new RealtimeSessionService();
|
|
16
|
-
executeGQL = vi.fn(async () => ({ CancelRealtimeSessionTool: { AbortedCount: 1, Success: true } }));
|
|
17
|
-
service.Provider = { ExecuteGQL: executeGQL };
|
|
18
|
-
internals(service).agentSessionId = 'sess-1';
|
|
19
|
-
internals(service).inFlightCallIds.add('call-1');
|
|
20
|
-
});
|
|
21
|
-
it('calls the CancelRealtimeSessionTool mutation with the session + call id, selecting the structured result', async () => {
|
|
22
|
-
await service.CancelDelegation('call-1');
|
|
23
|
-
expect(executeGQL).toHaveBeenCalledTimes(1);
|
|
24
|
-
expect(executeGQL).toHaveBeenCalledWith(expect.stringContaining('CancelRealtimeSessionTool'), { agentSessionId: 'sess-1', callId: 'call-1' });
|
|
25
|
-
// The mutation document selects the structured result fields (server contract).
|
|
26
|
-
const mutation = executeGQL.mock.calls[0][0];
|
|
27
|
-
expect(mutation).toContain('AbortedCount');
|
|
28
|
-
expect(mutation).toContain('Success');
|
|
29
|
-
expect(mutation).toContain('ErrorMessage');
|
|
30
|
-
});
|
|
31
|
-
it('flips the card to a FAILED "Cancelled by user" result when the server aborted the run', async () => {
|
|
32
|
-
const results = collectResults(service);
|
|
33
|
-
const ok = await service.CancelDelegation('call-1');
|
|
34
|
-
expect(ok).toBe(true);
|
|
35
|
-
expect(results).toEqual([{ CallID: 'call-1', Success: false, Output: 'Cancelled by user' }]);
|
|
36
|
-
expect(internals(service).inFlightCallIds.has('call-1')).toBe(false);
|
|
37
|
-
});
|
|
38
|
-
it('suppresses the aborted run\'s LATE real result so it cannot overwrite the cancelled card', async () => {
|
|
39
|
-
const results = collectResults(service);
|
|
40
|
-
await service.CancelDelegation('call-1');
|
|
41
|
-
// The original ExecuteRealtimeSessionTool mutation eventually resolves with the aborted outcome.
|
|
42
|
-
internals(service).emitDelegationResult('call-1', JSON.stringify({ success: false, error: 'Delegation failed: aborted' }));
|
|
43
|
-
expect(results).toHaveLength(1); // only the "Cancelled by user" card flip
|
|
44
|
-
expect(internals(service).cancelledCallIds.size).toBe(0); // the suppression marker was consumed
|
|
45
|
-
});
|
|
46
|
-
it('a DIFFERENT call\'s result still emits normally after a cancel', async () => {
|
|
47
|
-
const results = collectResults(service);
|
|
48
|
-
internals(service).inFlightCallIds.add('call-2');
|
|
49
|
-
await service.CancelDelegation('call-1');
|
|
50
|
-
internals(service).emitDelegationResult('call-2', JSON.stringify({ success: true, output: 'done' }));
|
|
51
|
-
expect(results).toHaveLength(2);
|
|
52
|
-
expect(results[1]).toMatchObject({ CallID: 'call-2', Success: true, Output: 'done' });
|
|
53
|
-
});
|
|
54
|
-
it('returns false WITHOUT flipping the card when the server had nothing to abort (result is racing in)', async () => {
|
|
55
|
-
executeGQL.mockResolvedValue({ CancelRealtimeSessionTool: { AbortedCount: 0, Success: true } });
|
|
56
|
-
const results = collectResults(service);
|
|
57
|
-
const ok = await service.CancelDelegation('call-1');
|
|
58
|
-
expect(ok).toBe(false);
|
|
59
|
-
expect(results).toEqual([]);
|
|
60
|
-
// The call stays tracked so the racing real result is processed normally.
|
|
61
|
-
expect(internals(service).inFlightCallIds.has('call-1')).toBe(true);
|
|
62
|
-
});
|
|
63
|
-
it('treats a STRUCTURED failure (Success: false) as nothing aborted — card untouched', async () => {
|
|
64
|
-
executeGQL.mockResolvedValue({
|
|
65
|
-
CancelRealtimeSessionTool: { AbortedCount: 0, Success: false, ErrorMessage: 'registry exploded' },
|
|
66
|
-
});
|
|
67
|
-
const results = collectResults(service);
|
|
68
|
-
const ok = await service.CancelDelegation('call-1');
|
|
69
|
-
expect(ok).toBe(false);
|
|
70
|
-
expect(results).toEqual([]);
|
|
71
|
-
expect(internals(service).inFlightCallIds.has('call-1')).toBe(true);
|
|
72
|
-
});
|
|
73
|
-
it('is a no-op (no mutation) for a call id that is not tracked in flight', async () => {
|
|
74
|
-
const ok = await service.CancelDelegation('call-unknown');
|
|
75
|
-
expect(ok).toBe(false);
|
|
76
|
-
expect(executeGQL).not.toHaveBeenCalled();
|
|
77
|
-
});
|
|
78
|
-
it('is a no-op (no mutation) when no session is open', async () => {
|
|
79
|
-
internals(service).agentSessionId = null;
|
|
80
|
-
const ok = await service.CancelDelegation('call-1');
|
|
81
|
-
expect(ok).toBe(false);
|
|
82
|
-
expect(executeGQL).not.toHaveBeenCalled();
|
|
83
|
-
});
|
|
84
|
-
it('tolerates a failed mutation (false, logged, card untouched)', async () => {
|
|
85
|
-
executeGQL.mockRejectedValue(new Error('network down'));
|
|
86
|
-
const results = collectResults(service);
|
|
87
|
-
const ok = await service.CancelDelegation('call-1');
|
|
88
|
-
expect(ok).toBe(false);
|
|
89
|
-
expect(results).toEqual([]);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
describe('RealtimeSessionService — CancelInFlightDelegations (sweep cancel)', () => {
|
|
93
|
-
let service;
|
|
94
|
-
let executeGQL;
|
|
95
|
-
beforeEach(() => {
|
|
96
|
-
service = new RealtimeSessionService();
|
|
97
|
-
executeGQL = vi.fn(async () => ({ CancelRealtimeSessionTool: { AbortedCount: 2, Success: true } }));
|
|
98
|
-
service.Provider = { ExecuteGQL: executeGQL };
|
|
99
|
-
internals(service).agentSessionId = 'sess-1';
|
|
100
|
-
});
|
|
101
|
-
it('cancels ALL tracked in-flight calls with ONE callId-less mutation and flips every card', async () => {
|
|
102
|
-
internals(service).inFlightCallIds.add('call-1');
|
|
103
|
-
internals(service).inFlightCallIds.add('call-2');
|
|
104
|
-
const results = collectResults(service);
|
|
105
|
-
const count = await service.CancelInFlightDelegations();
|
|
106
|
-
expect(count).toBe(2);
|
|
107
|
-
expect(executeGQL).toHaveBeenCalledTimes(1);
|
|
108
|
-
expect(executeGQL).toHaveBeenCalledWith(expect.stringContaining('CancelRealtimeSessionTool'), { agentSessionId: 'sess-1', callId: null });
|
|
109
|
-
expect(results.map(r => r.CallID).sort()).toEqual(['call-1', 'call-2']);
|
|
110
|
-
expect(results.every(r => !r.Success && r.Output === 'Cancelled by user')).toBe(true);
|
|
111
|
-
expect(internals(service).inFlightCallIds.size).toBe(0);
|
|
112
|
-
});
|
|
113
|
-
it('returns 0 without a mutation when nothing is tracked in flight', async () => {
|
|
114
|
-
const count = await service.CancelInFlightDelegations();
|
|
115
|
-
expect(count).toBe(0);
|
|
116
|
-
expect(executeGQL).not.toHaveBeenCalled();
|
|
117
|
-
});
|
|
118
|
-
it('returns 0 (cards untouched) when the server aborted nothing', async () => {
|
|
119
|
-
executeGQL.mockResolvedValue({ CancelRealtimeSessionTool: { AbortedCount: 0, Success: true } });
|
|
120
|
-
internals(service).inFlightCallIds.add('call-1');
|
|
121
|
-
const results = collectResults(service);
|
|
122
|
-
const count = await service.CancelInFlightDelegations();
|
|
123
|
-
expect(count).toBe(0);
|
|
124
|
-
expect(results).toEqual([]);
|
|
125
|
-
expect(internals(service).inFlightCallIds.has('call-1')).toBe(true);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
describe('RealtimeSessionService — usage telemetry relay (OnUsage → RelayRealtimeUsage)', () => {
|
|
129
|
-
let service;
|
|
130
|
-
let executeGQL;
|
|
131
|
-
beforeEach(() => {
|
|
132
|
-
vi.useFakeTimers();
|
|
133
|
-
service = new RealtimeSessionService();
|
|
134
|
-
executeGQL = vi.fn(async () => ({ RelayRealtimeUsage: true }));
|
|
135
|
-
service.Provider = { ExecuteGQL: executeGQL };
|
|
136
|
-
internals(service).agentSessionId = 'sess-1';
|
|
137
|
-
});
|
|
138
|
-
afterEach(() => {
|
|
139
|
-
vi.useRealTimers();
|
|
140
|
-
});
|
|
141
|
-
it('accumulates deltas and relays ONE debounced mutation (~10s) with the summed totals', async () => {
|
|
142
|
-
internals(service).onUsageDelta({ InputTokens: 100, OutputTokens: 10 });
|
|
143
|
-
internals(service).onUsageDelta({ InputTokens: 20, OutputTokens: 5 });
|
|
144
|
-
await vi.advanceTimersByTimeAsync(9999);
|
|
145
|
-
expect(executeGQL).not.toHaveBeenCalled();
|
|
146
|
-
await vi.advanceTimersByTimeAsync(1);
|
|
147
|
-
expect(executeGQL).toHaveBeenCalledTimes(1);
|
|
148
|
-
expect(executeGQL).toHaveBeenCalledWith(expect.stringContaining('RelayRealtimeUsage'), { agentSessionId: 'sess-1', inputTokens: 120, outputTokens: 15 });
|
|
149
|
-
// Accumulators were consumed by the flush.
|
|
150
|
-
expect(internals(service).pendingUsageInput).toBe(0);
|
|
151
|
-
expect(internals(service).pendingUsageOutput).toBe(0);
|
|
152
|
-
});
|
|
153
|
-
it('ignores all-zero / negative / missing deltas (no timer armed, no mutation)', async () => {
|
|
154
|
-
internals(service).onUsageDelta({});
|
|
155
|
-
internals(service).onUsageDelta({ InputTokens: -5, OutputTokens: 0 });
|
|
156
|
-
internals(service).onUsageDelta({ InputTokens: Number.NaN });
|
|
157
|
-
await vi.advanceTimersByTimeAsync(60000);
|
|
158
|
-
expect(executeGQL).not.toHaveBeenCalled();
|
|
159
|
-
expect(internals(service).usageFlushTimer).toBeNull();
|
|
160
|
-
});
|
|
161
|
-
it('clamps a negative component while accumulating the positive one', async () => {
|
|
162
|
-
internals(service).onUsageDelta({ InputTokens: -3, OutputTokens: 7 });
|
|
163
|
-
await vi.advanceTimersByTimeAsync(10000);
|
|
164
|
-
expect(executeGQL).toHaveBeenCalledWith(expect.stringContaining('RelayRealtimeUsage'), { agentSessionId: 'sess-1', inputTokens: 0, outputTokens: 7 });
|
|
165
|
-
});
|
|
166
|
-
it('re-accumulates on a failed relay so the next flush retries the same deltas', async () => {
|
|
167
|
-
executeGQL.mockRejectedValueOnce(new Error('network down'));
|
|
168
|
-
internals(service).onUsageDelta({ InputTokens: 50, OutputTokens: 5 });
|
|
169
|
-
await vi.advanceTimersByTimeAsync(10000); // flush fails
|
|
170
|
-
expect(internals(service).pendingUsageInput).toBe(50);
|
|
171
|
-
expect(internals(service).pendingUsageOutput).toBe(5);
|
|
172
|
-
internals(service).onUsageDelta({ InputTokens: 10, OutputTokens: 0 });
|
|
173
|
-
await vi.advanceTimersByTimeAsync(10000); // retry carries the combined totals
|
|
174
|
-
expect(executeGQL).toHaveBeenLastCalledWith(expect.stringContaining('RelayRealtimeUsage'), { agentSessionId: 'sess-1', inputTokens: 60, outputTokens: 5 });
|
|
175
|
-
});
|
|
176
|
-
it('flushes the unrelayed remainder at teardown BEFORE closing the server session (no debounce wait)', async () => {
|
|
177
|
-
internals(service).onUsageDelta({ InputTokens: 33, OutputTokens: 4 });
|
|
178
|
-
await internals(service).teardown(true);
|
|
179
|
-
const mutations = executeGQL.mock.calls.map(c => c[0]);
|
|
180
|
-
const usageIdx = mutations.findIndex(m => m.includes('RelayRealtimeUsage'));
|
|
181
|
-
const closeIdx = mutations.findIndex(m => m.includes('CloseAgentSession'));
|
|
182
|
-
expect(usageIdx).toBeGreaterThanOrEqual(0);
|
|
183
|
-
expect(closeIdx).toBeGreaterThan(usageIdx); // usage flushed first, then close
|
|
184
|
-
expect(executeGQL.mock.calls[usageIdx][1]).toEqual({ agentSessionId: 'sess-1', inputTokens: 33, outputTokens: 4 });
|
|
185
|
-
// Teardown leaves the relay reset (no dangling timer / pending totals).
|
|
186
|
-
expect(internals(service).usageFlushTimer).toBeNull();
|
|
187
|
-
expect(internals(service).pendingUsageInput).toBe(0);
|
|
188
|
-
expect(internals(service).pendingUsageOutput).toBe(0);
|
|
189
|
-
});
|
|
190
|
-
it('teardown without pending usage relays nothing (no spurious zero-delta mutation)', async () => {
|
|
191
|
-
await internals(service).teardown(true);
|
|
192
|
-
const mutations = executeGQL.mock.calls.map(c => c[0]);
|
|
193
|
-
expect(mutations.some(m => m.includes('RelayRealtimeUsage'))).toBe(false);
|
|
194
|
-
expect(mutations.some(m => m.includes('CloseAgentSession'))).toBe(true);
|
|
195
|
-
});
|
|
196
|
-
it('flushPendingUsage is a no-op without a session id', async () => {
|
|
197
|
-
internals(service).agentSessionId = null;
|
|
198
|
-
internals(service).onUsageDelta({ InputTokens: 9 });
|
|
199
|
-
await internals(service).flushPendingUsage();
|
|
200
|
-
expect(executeGQL).not.toHaveBeenCalled();
|
|
201
|
-
// The deltas survive for a later flush once a session id exists.
|
|
202
|
-
expect(internals(service).pendingUsageInput).toBe(9);
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
describe('RealtimeSessionService — OnUsage wiring through wireClientHandlers', () => {
|
|
206
|
-
/** Fake client capturing every handler wireClientHandlers registers. */
|
|
207
|
-
class FakeWiredClient {
|
|
208
|
-
UsageHandler = null;
|
|
209
|
-
OnStateChange() { }
|
|
210
|
-
OnTranscript() { }
|
|
211
|
-
OnToolCall() { }
|
|
212
|
-
OnError() { }
|
|
213
|
-
OnInterruption() { }
|
|
214
|
-
OnUsage(handler) {
|
|
215
|
-
this.UsageHandler = handler;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
it('registers an OnUsage handler that feeds the accumulator', () => {
|
|
219
|
-
const service = new RealtimeSessionService();
|
|
220
|
-
const seam = service;
|
|
221
|
-
seam.agentSessionId = 'sess-1';
|
|
222
|
-
const client = new FakeWiredClient();
|
|
223
|
-
seam.wireClientHandlers(client);
|
|
224
|
-
expect(client.UsageHandler).toBeTypeOf('function');
|
|
225
|
-
client.UsageHandler?.({ InputTokens: 11, OutputTokens: 3 });
|
|
226
|
-
expect(seam.pendingUsageInput).toBe(11);
|
|
227
|
-
expect(seam.pendingUsageOutput).toBe(3);
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
//# sourceMappingURL=realtime-session-cancel-usage.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-session-cancel-usage.test.js","sourceRoot":"","sources":["../../src/__tests__/realtime-session-cancel-usage.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';\nimport { IMetadataProvider } from '@memberjunction/core';\nimport { RealtimeClientUsage } from '@memberjunction/ai-realtime-client';\nimport { RealtimeSessionService, VoiceDelegationResult } from '../lib/services/realtime-session.service';\n\n/**\n * The explicit delegation-CANCEL channel ({@link RealtimeSessionService.CancelDelegation} /\n * {@link RealtimeSessionService.CancelInFlightDelegations}) and the usage-telemetry relay\n * (`OnUsage` deltas → debounced `RelayRealtimeUsage` + teardown flush).\n *\n * Same narrow typed-seam approach as the sibling voice-session suites: a fake Provider whose\n * `ExecuteGQL` captures mutations, with private members reached through a typed internals cast.\n */\n\n/** The private surface the tests drive — no `any`, just the members under test. */\ninterface RealtimeSessionCancelUsageInternals {\n agentSessionId: string | null;\n inFlightCallIds: Set<string>;\n cancelledCallIds: Set<string>;\n pendingUsageInput: number;\n pendingUsageOutput: number;\n usageFlushTimer: ReturnType<typeof setTimeout> | null;\n emitDelegationResult(callId: string, resultJson: string): void;\n onUsageDelta(usage: RealtimeClientUsage): void;\n flushPendingUsage(agentSessionId?: string | null): Promise<void>;\n teardown(closeServerSession: boolean): Promise<void>;\n}\n\nfunction internals(service: RealtimeSessionService): RealtimeSessionCancelUsageInternals {\n return service as unknown as RealtimeSessionCancelUsageInternals;\n}\n\nfunction collectResults(service: RealtimeSessionService): VoiceDelegationResult[] {\n const results: VoiceDelegationResult[] = [];\n service.DelegationResult$.subscribe(r => results.push(r));\n return results;\n}\n\ndescribe('RealtimeSessionService — CancelDelegation (per-card ✕, explicit user intent)', () => {\n let service: RealtimeSessionService;\n let executeGQL: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n service = new RealtimeSessionService();\n executeGQL = vi.fn(async () => ({ CancelRealtimeSessionTool: { AbortedCount: 1, Success: true } }));\n service.Provider = { ExecuteGQL: executeGQL } as unknown as IMetadataProvider;\n internals(service).agentSessionId = 'sess-1';\n internals(service).inFlightCallIds.add('call-1');\n });\n\n it('calls the CancelRealtimeSessionTool mutation with the session + call id, selecting the structured result', async () => {\n await service.CancelDelegation('call-1');\n\n expect(executeGQL).toHaveBeenCalledTimes(1);\n expect(executeGQL).toHaveBeenCalledWith(\n expect.stringContaining('CancelRealtimeSessionTool'),\n { agentSessionId: 'sess-1', callId: 'call-1' }\n );\n // The mutation document selects the structured result fields (server contract).\n const mutation = executeGQL.mock.calls[0][0] as string;\n expect(mutation).toContain('AbortedCount');\n expect(mutation).toContain('Success');\n expect(mutation).toContain('ErrorMessage');\n });\n\n it('flips the card to a FAILED \"Cancelled by user\" result when the server aborted the run', async () => {\n const results = collectResults(service);\n\n const ok = await service.CancelDelegation('call-1');\n\n expect(ok).toBe(true);\n expect(results).toEqual([{ CallID: 'call-1', Success: false, Output: 'Cancelled by user' }]);\n expect(internals(service).inFlightCallIds.has('call-1')).toBe(false);\n });\n\n it('suppresses the aborted run\\'s LATE real result so it cannot overwrite the cancelled card', async () => {\n const results = collectResults(service);\n await service.CancelDelegation('call-1');\n\n // The original ExecuteRealtimeSessionTool mutation eventually resolves with the aborted outcome.\n internals(service).emitDelegationResult('call-1', JSON.stringify({ success: false, error: 'Delegation failed: aborted' }));\n\n expect(results).toHaveLength(1); // only the \"Cancelled by user\" card flip\n expect(internals(service).cancelledCallIds.size).toBe(0); // the suppression marker was consumed\n });\n\n it('a DIFFERENT call\\'s result still emits normally after a cancel', async () => {\n const results = collectResults(service);\n internals(service).inFlightCallIds.add('call-2');\n await service.CancelDelegation('call-1');\n\n internals(service).emitDelegationResult('call-2', JSON.stringify({ success: true, output: 'done' }));\n\n expect(results).toHaveLength(2);\n expect(results[1]).toMatchObject({ CallID: 'call-2', Success: true, Output: 'done' });\n });\n\n it('returns false WITHOUT flipping the card when the server had nothing to abort (result is racing in)', async () => {\n executeGQL.mockResolvedValue({ CancelRealtimeSessionTool: { AbortedCount: 0, Success: true } });\n const results = collectResults(service);\n\n const ok = await service.CancelDelegation('call-1');\n\n expect(ok).toBe(false);\n expect(results).toEqual([]);\n // The call stays tracked so the racing real result is processed normally.\n expect(internals(service).inFlightCallIds.has('call-1')).toBe(true);\n });\n\n it('treats a STRUCTURED failure (Success: false) as nothing aborted — card untouched', async () => {\n executeGQL.mockResolvedValue({\n CancelRealtimeSessionTool: { AbortedCount: 0, Success: false, ErrorMessage: 'registry exploded' },\n });\n const results = collectResults(service);\n\n const ok = await service.CancelDelegation('call-1');\n\n expect(ok).toBe(false);\n expect(results).toEqual([]);\n expect(internals(service).inFlightCallIds.has('call-1')).toBe(true);\n });\n\n it('is a no-op (no mutation) for a call id that is not tracked in flight', async () => {\n const ok = await service.CancelDelegation('call-unknown');\n expect(ok).toBe(false);\n expect(executeGQL).not.toHaveBeenCalled();\n });\n\n it('is a no-op (no mutation) when no session is open', async () => {\n internals(service).agentSessionId = null;\n const ok = await service.CancelDelegation('call-1');\n expect(ok).toBe(false);\n expect(executeGQL).not.toHaveBeenCalled();\n });\n\n it('tolerates a failed mutation (false, logged, card untouched)', async () => {\n executeGQL.mockRejectedValue(new Error('network down'));\n const results = collectResults(service);\n\n const ok = await service.CancelDelegation('call-1');\n\n expect(ok).toBe(false);\n expect(results).toEqual([]);\n });\n});\n\ndescribe('RealtimeSessionService — CancelInFlightDelegations (sweep cancel)', () => {\n let service: RealtimeSessionService;\n let executeGQL: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n service = new RealtimeSessionService();\n executeGQL = vi.fn(async () => ({ CancelRealtimeSessionTool: { AbortedCount: 2, Success: true } }));\n service.Provider = { ExecuteGQL: executeGQL } as unknown as IMetadataProvider;\n internals(service).agentSessionId = 'sess-1';\n });\n\n it('cancels ALL tracked in-flight calls with ONE callId-less mutation and flips every card', async () => {\n internals(service).inFlightCallIds.add('call-1');\n internals(service).inFlightCallIds.add('call-2');\n const results = collectResults(service);\n\n const count = await service.CancelInFlightDelegations();\n\n expect(count).toBe(2);\n expect(executeGQL).toHaveBeenCalledTimes(1);\n expect(executeGQL).toHaveBeenCalledWith(\n expect.stringContaining('CancelRealtimeSessionTool'),\n { agentSessionId: 'sess-1', callId: null }\n );\n expect(results.map(r => r.CallID).sort()).toEqual(['call-1', 'call-2']);\n expect(results.every(r => !r.Success && r.Output === 'Cancelled by user')).toBe(true);\n expect(internals(service).inFlightCallIds.size).toBe(0);\n });\n\n it('returns 0 without a mutation when nothing is tracked in flight', async () => {\n const count = await service.CancelInFlightDelegations();\n expect(count).toBe(0);\n expect(executeGQL).not.toHaveBeenCalled();\n });\n\n it('returns 0 (cards untouched) when the server aborted nothing', async () => {\n executeGQL.mockResolvedValue({ CancelRealtimeSessionTool: { AbortedCount: 0, Success: true } });\n internals(service).inFlightCallIds.add('call-1');\n const results = collectResults(service);\n\n const count = await service.CancelInFlightDelegations();\n\n expect(count).toBe(0);\n expect(results).toEqual([]);\n expect(internals(service).inFlightCallIds.has('call-1')).toBe(true);\n });\n});\n\ndescribe('RealtimeSessionService — usage telemetry relay (OnUsage → RelayRealtimeUsage)', () => {\n let service: RealtimeSessionService;\n let executeGQL: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n vi.useFakeTimers();\n service = new RealtimeSessionService();\n executeGQL = vi.fn(async () => ({ RelayRealtimeUsage: true }));\n service.Provider = { ExecuteGQL: executeGQL } as unknown as IMetadataProvider;\n internals(service).agentSessionId = 'sess-1';\n });\n\n afterEach(() => {\n vi.useRealTimers();\n });\n\n it('accumulates deltas and relays ONE debounced mutation (~10s) with the summed totals', async () => {\n internals(service).onUsageDelta({ InputTokens: 100, OutputTokens: 10 });\n internals(service).onUsageDelta({ InputTokens: 20, OutputTokens: 5 });\n\n await vi.advanceTimersByTimeAsync(9999);\n expect(executeGQL).not.toHaveBeenCalled();\n\n await vi.advanceTimersByTimeAsync(1);\n expect(executeGQL).toHaveBeenCalledTimes(1);\n expect(executeGQL).toHaveBeenCalledWith(\n expect.stringContaining('RelayRealtimeUsage'),\n { agentSessionId: 'sess-1', inputTokens: 120, outputTokens: 15 }\n );\n // Accumulators were consumed by the flush.\n expect(internals(service).pendingUsageInput).toBe(0);\n expect(internals(service).pendingUsageOutput).toBe(0);\n });\n\n it('ignores all-zero / negative / missing deltas (no timer armed, no mutation)', async () => {\n internals(service).onUsageDelta({});\n internals(service).onUsageDelta({ InputTokens: -5, OutputTokens: 0 });\n internals(service).onUsageDelta({ InputTokens: Number.NaN });\n\n await vi.advanceTimersByTimeAsync(60000);\n expect(executeGQL).not.toHaveBeenCalled();\n expect(internals(service).usageFlushTimer).toBeNull();\n });\n\n it('clamps a negative component while accumulating the positive one', async () => {\n internals(service).onUsageDelta({ InputTokens: -3, OutputTokens: 7 });\n\n await vi.advanceTimersByTimeAsync(10000);\n expect(executeGQL).toHaveBeenCalledWith(\n expect.stringContaining('RelayRealtimeUsage'),\n { agentSessionId: 'sess-1', inputTokens: 0, outputTokens: 7 }\n );\n });\n\n it('re-accumulates on a failed relay so the next flush retries the same deltas', async () => {\n executeGQL.mockRejectedValueOnce(new Error('network down'));\n internals(service).onUsageDelta({ InputTokens: 50, OutputTokens: 5 });\n await vi.advanceTimersByTimeAsync(10000); // flush fails\n\n expect(internals(service).pendingUsageInput).toBe(50);\n expect(internals(service).pendingUsageOutput).toBe(5);\n\n internals(service).onUsageDelta({ InputTokens: 10, OutputTokens: 0 });\n await vi.advanceTimersByTimeAsync(10000); // retry carries the combined totals\n\n expect(executeGQL).toHaveBeenLastCalledWith(\n expect.stringContaining('RelayRealtimeUsage'),\n { agentSessionId: 'sess-1', inputTokens: 60, outputTokens: 5 }\n );\n });\n\n it('flushes the unrelayed remainder at teardown BEFORE closing the server session (no debounce wait)', async () => {\n internals(service).onUsageDelta({ InputTokens: 33, OutputTokens: 4 });\n\n await internals(service).teardown(true);\n\n const mutations = executeGQL.mock.calls.map(c => c[0] as string);\n const usageIdx = mutations.findIndex(m => m.includes('RelayRealtimeUsage'));\n const closeIdx = mutations.findIndex(m => m.includes('CloseAgentSession'));\n expect(usageIdx).toBeGreaterThanOrEqual(0);\n expect(closeIdx).toBeGreaterThan(usageIdx); // usage flushed first, then close\n expect(executeGQL.mock.calls[usageIdx][1]).toEqual({ agentSessionId: 'sess-1', inputTokens: 33, outputTokens: 4 });\n // Teardown leaves the relay reset (no dangling timer / pending totals).\n expect(internals(service).usageFlushTimer).toBeNull();\n expect(internals(service).pendingUsageInput).toBe(0);\n expect(internals(service).pendingUsageOutput).toBe(0);\n });\n\n it('teardown without pending usage relays nothing (no spurious zero-delta mutation)', async () => {\n await internals(service).teardown(true);\n\n const mutations = executeGQL.mock.calls.map(c => c[0] as string);\n expect(mutations.some(m => m.includes('RelayRealtimeUsage'))).toBe(false);\n expect(mutations.some(m => m.includes('CloseAgentSession'))).toBe(true);\n });\n\n it('flushPendingUsage is a no-op without a session id', async () => {\n internals(service).agentSessionId = null;\n internals(service).onUsageDelta({ InputTokens: 9 });\n\n await internals(service).flushPendingUsage();\n\n expect(executeGQL).not.toHaveBeenCalled();\n // The deltas survive for a later flush once a session id exists.\n expect(internals(service).pendingUsageInput).toBe(9);\n });\n});\n\ndescribe('RealtimeSessionService — OnUsage wiring through wireClientHandlers', () => {\n /** Fake client capturing every handler wireClientHandlers registers. */\n class FakeWiredClient {\n public UsageHandler: ((u: RealtimeClientUsage) => void) | null = null;\n OnStateChange(): void { /* captured elsewhere */ }\n OnTranscript(): void { /* not exercised */ }\n OnToolCall(): void { /* not exercised */ }\n OnError(): void { /* not exercised */ }\n OnInterruption(): void { /* not exercised */ }\n OnUsage(handler: (u: RealtimeClientUsage) => void): void {\n this.UsageHandler = handler;\n }\n }\n\n interface WiringInternals {\n agentSessionId: string | null;\n pendingUsageInput: number;\n pendingUsageOutput: number;\n wireClientHandlers(client: FakeWiredClient): void;\n }\n\n it('registers an OnUsage handler that feeds the accumulator', () => {\n const service = new RealtimeSessionService();\n const seam = service as unknown as WiringInternals;\n seam.agentSessionId = 'sess-1';\n const client = new FakeWiredClient();\n\n seam.wireClientHandlers(client);\n expect(client.UsageHandler).toBeTypeOf('function');\n\n client.UsageHandler?.({ InputTokens: 11, OutputTokens: 3 });\n expect(seam.pendingUsageInput).toBe(11);\n expect(seam.pendingUsageOutput).toBe(3);\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-session-channels.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/realtime-session-channels.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,252 +0,0 @@
|
|
|
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 { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
8
|
-
import { AIEngineBase } from '@memberjunction/ai-engine-base';
|
|
9
|
-
import { RegisterClass } from '@memberjunction/global';
|
|
10
|
-
import { RealtimeSessionService } from '../lib/services/realtime-session.service';
|
|
11
|
-
import { BaseRealtimeChannelClient } from '../lib/components/realtime/channels/base-realtime-channel-client';
|
|
12
|
-
class FakeRealtimeClient {
|
|
13
|
-
ToolResults = [];
|
|
14
|
-
SendToolResult(callId, resultJson) {
|
|
15
|
-
this.ToolResults.push({ CallID: callId, ResultJson: resultJson });
|
|
16
|
-
}
|
|
17
|
-
SendContextNote(_text) {
|
|
18
|
-
// not under test here
|
|
19
|
-
}
|
|
20
|
-
async Disconnect() {
|
|
21
|
-
// no-op for teardown
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function internals(service) {
|
|
25
|
-
return service;
|
|
26
|
-
}
|
|
27
|
-
/** A minimal surface stand-in (never instantiated by these node tests). */
|
|
28
|
-
class FakeSurface {
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* A fake interactive-channel plugin, registered exactly like production plugins
|
|
32
|
-
* (`@RegisterClass(BaseRealtimeChannelClient, '<ClientPluginClass>')`).
|
|
33
|
-
*/
|
|
34
|
-
let TestEchoChannel = class TestEchoChannel extends BaseRealtimeChannelClient {
|
|
35
|
-
AppliedCalls = [];
|
|
36
|
-
Disposed = false;
|
|
37
|
-
BoundSurface = null;
|
|
38
|
-
get ChannelName() {
|
|
39
|
-
return 'Echo';
|
|
40
|
-
}
|
|
41
|
-
get ToolNamePrefix() {
|
|
42
|
-
return 'Echo.';
|
|
43
|
-
}
|
|
44
|
-
get TabTitle() {
|
|
45
|
-
return 'Echo';
|
|
46
|
-
}
|
|
47
|
-
get TabIcon() {
|
|
48
|
-
return 'fa-solid fa-microphone';
|
|
49
|
-
}
|
|
50
|
-
GetToolDefinitions() {
|
|
51
|
-
return [
|
|
52
|
-
{ Name: 'Echo.Say', Description: 'Echo a phrase', ParametersSchema: { type: 'object' } },
|
|
53
|
-
{ Name: 'Echo.Clear', Description: 'Clear echoes', ParametersSchema: { type: 'object' } }
|
|
54
|
-
];
|
|
55
|
-
}
|
|
56
|
-
GetSurfaceComponent() {
|
|
57
|
-
return FakeSurface;
|
|
58
|
-
}
|
|
59
|
-
BindSurface(instance) {
|
|
60
|
-
this.BoundSurface = instance;
|
|
61
|
-
}
|
|
62
|
-
ApplyAgentTool(toolName, argsJson) {
|
|
63
|
-
this.AppliedCalls.push({ ToolName: toolName, ArgsJson: argsJson });
|
|
64
|
-
return JSON.stringify({ success: true, echoed: toolName });
|
|
65
|
-
}
|
|
66
|
-
Dispose() {
|
|
67
|
-
this.Disposed = true;
|
|
68
|
-
super.Dispose();
|
|
69
|
-
}
|
|
70
|
-
/** Test seam: expose the host context the service handed us. */
|
|
71
|
-
get Ctx() {
|
|
72
|
-
return this.Context;
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
TestEchoChannel = __decorate([
|
|
76
|
-
RegisterClass(BaseRealtimeChannelClient, 'TestEchoChannel')
|
|
77
|
-
], TestEchoChannel);
|
|
78
|
-
/**
|
|
79
|
-
* Stubs the provider-scoped AIEngineBase whose cached `AgentChannels` the service reads
|
|
80
|
-
* (rows default to ACTIVE; pass `IsActive: false` to exercise the active-only filter).
|
|
81
|
-
* `success = false` makes the engine load reject — the registry-failure degradation path.
|
|
82
|
-
*/
|
|
83
|
-
function mockChannelRegistry(rows, success = true) {
|
|
84
|
-
const configFn = vi.fn(async () => {
|
|
85
|
-
if (!success) {
|
|
86
|
-
throw new Error('boom');
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
const fakeEngine = {
|
|
90
|
-
Config: configFn,
|
|
91
|
-
get AgentChannels() {
|
|
92
|
-
return rows.map(r => ({ IsActive: true, ...r }));
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
vi.spyOn(AIEngineBase, 'GetProviderInstance').mockReturnValue(fakeEngine);
|
|
96
|
-
return configFn;
|
|
97
|
-
}
|
|
98
|
-
describe('RealtimeSessionService — interactive-channel registry resolution', () => {
|
|
99
|
-
let service;
|
|
100
|
-
beforeEach(() => {
|
|
101
|
-
service = new RealtimeSessionService();
|
|
102
|
-
});
|
|
103
|
-
afterEach(() => {
|
|
104
|
-
vi.restoreAllMocks();
|
|
105
|
-
});
|
|
106
|
-
it('resolves ACTIVE registry rows into per-session plugin instances via the ClassFactory', async () => {
|
|
107
|
-
const configFn = mockChannelRegistry([
|
|
108
|
-
{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' },
|
|
109
|
-
// Inactive rows never become session plugins (parity with the old `IsActive = 1` filter).
|
|
110
|
-
{ ID: 'c2', Name: 'Dormant', ClientPluginClass: 'TestEchoChannel', IsActive: false }
|
|
111
|
-
]);
|
|
112
|
-
await internals(service).startChannels();
|
|
113
|
-
// Lazily configures the provider-scoped engine before reading the cached registry.
|
|
114
|
-
expect(configFn).toHaveBeenCalledWith(false, undefined, service.Provider);
|
|
115
|
-
expect(service.ActiveChannels).toHaveLength(1);
|
|
116
|
-
expect(service.ActiveChannels[0]).toBeInstanceOf(TestEchoChannel);
|
|
117
|
-
});
|
|
118
|
-
it('creates a FRESH instance per session (plugins are not singletons)', async () => {
|
|
119
|
-
mockChannelRegistry([{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }]);
|
|
120
|
-
await internals(service).startChannels();
|
|
121
|
-
const first = service.ActiveChannels[0];
|
|
122
|
-
await internals(service).startChannels();
|
|
123
|
-
expect(service.ActiveChannels[0]).not.toBe(first);
|
|
124
|
-
});
|
|
125
|
-
it('skips rows whose ClientPluginClass has no registration (logged, never fatal)', async () => {
|
|
126
|
-
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
127
|
-
mockChannelRegistry([
|
|
128
|
-
{ ID: 'c1', Name: 'Ghost', ClientPluginClass: 'NoSuchChannelPlugin' },
|
|
129
|
-
{ ID: 'c2', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }
|
|
130
|
-
]);
|
|
131
|
-
await internals(service).startChannels();
|
|
132
|
-
expect(service.ActiveChannels).toHaveLength(1);
|
|
133
|
-
expect(service.ActiveChannels[0]).toBeInstanceOf(TestEchoChannel);
|
|
134
|
-
expect(warn).toHaveBeenCalledWith(expect.stringContaining("No client plugin registered for channel 'Ghost'"));
|
|
135
|
-
});
|
|
136
|
-
it('degrades to NO channels when the registry load fails (the voice session must proceed)', async () => {
|
|
137
|
-
vi.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
138
|
-
mockChannelRegistry([], false);
|
|
139
|
-
const tools = await internals(service).startChannels();
|
|
140
|
-
expect(tools).toEqual([]);
|
|
141
|
-
expect(service.ActiveChannels).toEqual([]);
|
|
142
|
-
});
|
|
143
|
-
it('degrades to NO channels when the engine acquisition throws', async () => {
|
|
144
|
-
vi.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
145
|
-
vi.spyOn(AIEngineBase, 'GetProviderInstance').mockImplementation(() => {
|
|
146
|
-
throw new Error('no provider');
|
|
147
|
-
});
|
|
148
|
-
const tools = await internals(service).startChannels();
|
|
149
|
-
expect(tools).toEqual([]);
|
|
150
|
-
expect(service.ActiveChannels).toEqual([]);
|
|
151
|
-
});
|
|
152
|
-
it('aggregates every plugin tool definition into the clientTools set for the mint', async () => {
|
|
153
|
-
mockChannelRegistry([{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }]);
|
|
154
|
-
const tools = await internals(service).startChannels();
|
|
155
|
-
expect(tools.map(t => t.Name)).toEqual(['Echo.Say', 'Echo.Clear']);
|
|
156
|
-
});
|
|
157
|
-
it('emits the resolved plugins on ActiveChannels$ (the overlay registers tabs from it)', async () => {
|
|
158
|
-
mockChannelRegistry([{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }]);
|
|
159
|
-
const emissions = [];
|
|
160
|
-
const sub = service.ActiveChannels$.subscribe(channels => emissions.push(channels.length));
|
|
161
|
-
await internals(service).startChannels();
|
|
162
|
-
sub.unsubscribe();
|
|
163
|
-
expect(emissions).toEqual([0, 1]); // BehaviorSubject replay, then the resolved set
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
describe('RealtimeSessionService — per-plugin tool routing + host context', () => {
|
|
167
|
-
let service;
|
|
168
|
-
let fakeClient;
|
|
169
|
-
let plugin;
|
|
170
|
-
beforeEach(async () => {
|
|
171
|
-
service = new RealtimeSessionService();
|
|
172
|
-
fakeClient = new FakeRealtimeClient();
|
|
173
|
-
internals(service).client = fakeClient;
|
|
174
|
-
mockChannelRegistry([{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }]);
|
|
175
|
-
await internals(service).startChannels();
|
|
176
|
-
plugin = service.ActiveChannels[0];
|
|
177
|
-
});
|
|
178
|
-
afterEach(() => {
|
|
179
|
-
vi.restoreAllMocks();
|
|
180
|
-
});
|
|
181
|
-
it('routes prefix-matched tool calls to the plugin and feeds its result back to the model', async () => {
|
|
182
|
-
await internals(service).handleToolCall({ CallID: 'call-1', ToolName: 'Echo.Say', ArgumentsJson: '{"phrase":"hi"}' });
|
|
183
|
-
expect(plugin.AppliedCalls).toEqual([{ ToolName: 'Echo.Say', ArgsJson: '{"phrase":"hi"}' }]);
|
|
184
|
-
expect(fakeClient.ToolResults).toEqual([
|
|
185
|
-
{ CallID: 'call-1', ResultJson: JSON.stringify({ success: true, echoed: 'Echo.Say' }) }
|
|
186
|
-
]);
|
|
187
|
-
});
|
|
188
|
-
it('hands each plugin a context whose AgentName matches the session agent', () => {
|
|
189
|
-
expect(plugin.Ctx?.AgentName).toBe(service.CurrentAgentName);
|
|
190
|
-
});
|
|
191
|
-
it('SetFocusMode rides ChannelFocus$ tagged with the requesting plugin', () => {
|
|
192
|
-
const events = [];
|
|
193
|
-
const sub = service.ChannelFocus$.subscribe(e => events.push(e));
|
|
194
|
-
plugin.Ctx?.SetFocusMode(true);
|
|
195
|
-
plugin.Ctx?.SetFocusMode(false);
|
|
196
|
-
sub.unsubscribe();
|
|
197
|
-
expect(events).toEqual([
|
|
198
|
-
{ Channel: plugin, Focused: true },
|
|
199
|
-
{ Channel: plugin, Focused: false }
|
|
200
|
-
]);
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
describe('RealtimeSessionService — debounced channel saves + teardown flush/dispose', () => {
|
|
204
|
-
let service;
|
|
205
|
-
let plugin;
|
|
206
|
-
let saveSpy;
|
|
207
|
-
beforeEach(async () => {
|
|
208
|
-
vi.useFakeTimers();
|
|
209
|
-
service = new RealtimeSessionService();
|
|
210
|
-
internals(service).agentSessionId = 'session-123';
|
|
211
|
-
saveSpy = vi.spyOn(service, 'SaveChannelState').mockResolvedValue(true);
|
|
212
|
-
mockChannelRegistry([{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }]);
|
|
213
|
-
await internals(service).startChannels();
|
|
214
|
-
plugin = service.ActiveChannels[0];
|
|
215
|
-
});
|
|
216
|
-
afterEach(() => {
|
|
217
|
-
vi.useRealTimers();
|
|
218
|
-
vi.restoreAllMocks();
|
|
219
|
-
});
|
|
220
|
-
it('debounces RequestSave: a change burst becomes ONE save with the LATEST state', () => {
|
|
221
|
-
plugin.Ctx?.RequestSave('{"v":1}');
|
|
222
|
-
plugin.Ctx?.RequestSave('{"v":2}');
|
|
223
|
-
plugin.Ctx?.RequestSave('{"v":3}');
|
|
224
|
-
expect(saveSpy).not.toHaveBeenCalled();
|
|
225
|
-
vi.advanceTimersByTime(3000);
|
|
226
|
-
expect(saveSpy).toHaveBeenCalledTimes(1);
|
|
227
|
-
expect(saveSpy).toHaveBeenCalledWith('Echo', '{"v":3}', 'session-123');
|
|
228
|
-
});
|
|
229
|
-
it('teardown FLUSHES a pending save immediately (captured session id) and disposes plugins', async () => {
|
|
230
|
-
plugin.Ctx?.RequestSave('{"final":true}');
|
|
231
|
-
await internals(service).teardown(false);
|
|
232
|
-
expect(saveSpy).toHaveBeenCalledTimes(1);
|
|
233
|
-
expect(saveSpy).toHaveBeenCalledWith('Echo', '{"final":true}', 'session-123');
|
|
234
|
-
expect(plugin.Disposed).toBe(true);
|
|
235
|
-
expect(service.ActiveChannels).toEqual([]);
|
|
236
|
-
});
|
|
237
|
-
it('teardown with nothing pending saves nothing but still disposes', async () => {
|
|
238
|
-
await internals(service).teardown(false);
|
|
239
|
-
expect(saveSpy).not.toHaveBeenCalled();
|
|
240
|
-
expect(plugin.Disposed).toBe(true);
|
|
241
|
-
});
|
|
242
|
-
it('a Dispose error in one plugin is contained (teardown completes)', async () => {
|
|
243
|
-
const error = vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
244
|
-
vi.spyOn(plugin, 'Dispose').mockImplementation(() => {
|
|
245
|
-
throw new Error('plugin exploded');
|
|
246
|
-
});
|
|
247
|
-
await internals(service).teardown(false);
|
|
248
|
-
expect(service.ActiveChannels).toEqual([]);
|
|
249
|
-
expect(error).toHaveBeenCalledWith(expect.stringContaining("Channel 'Echo' Dispose failed"), expect.any(Error));
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
//# sourceMappingURL=realtime-session-channels.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-session-channels.test.js","sourceRoot":"","sources":["../../src/__tests__/realtime-session-channels.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect, beforeEach, afterEach, vi, type MockInstance } from 'vitest';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { RegisterClass } from '@memberjunction/global';\nimport { RealtimeToolDefinition } from '@memberjunction/ai';\nimport { RealtimeSessionService, RealtimeChannelFocusEvent } from '../lib/services/realtime-session.service';\nimport { BaseRealtimeChannelClient, RealtimeChannelContext } from '../lib/components/realtime/channels/base-realtime-channel-client';\n\n/**\n * INTERACTIVE-CHANNEL plumbing in the session service — the registry-driven plugin path:\n * `MJ: AI Agent Channels` rows → ClassFactory resolution by ClientPluginClass → per-session\n * plugin instances → tool aggregation + prefix-handler registration → debounced channel\n * saves → teardown flush + dispose. The service is channel-agnostic throughout; these tests\n * drive it with a FAKE channel plugin registered the same way real ones are.\n */\n\n/** The private surface the tests drive — no `any`, just the members under test. */\ninterface RealtimeSessionChannelInternals {\n client: FakeRealtimeClient | null;\n agentSessionId: string | null;\n startChannels(): Promise<RealtimeToolDefinition[]>;\n handleToolCall(call: { CallID: string; ToolName: string; ArgumentsJson: string }): Promise<void>;\n teardown(closeServerSession: boolean): Promise<void>;\n}\n\nclass FakeRealtimeClient {\n public ToolResults: Array<{ CallID: string; ResultJson: string }> = [];\n public SendToolResult(callId: string, resultJson: string): void {\n this.ToolResults.push({ CallID: callId, ResultJson: resultJson });\n }\n public SendContextNote(_text: string): void {\n // not under test here\n }\n public async Disconnect(): Promise<void> {\n // no-op for teardown\n }\n}\n\nfunction internals(service: RealtimeSessionService): RealtimeSessionChannelInternals {\n return service as unknown as RealtimeSessionChannelInternals;\n}\n\n/** A minimal surface stand-in (never instantiated by these node tests). */\nclass FakeSurface {}\n\n/**\n * A fake interactive-channel plugin, registered exactly like production plugins\n * (`@RegisterClass(BaseRealtimeChannelClient, '<ClientPluginClass>')`).\n */\n@RegisterClass(BaseRealtimeChannelClient, 'TestEchoChannel')\nclass TestEchoChannel extends BaseRealtimeChannelClient<FakeSurface> {\n public AppliedCalls: Array<{ ToolName: string; ArgsJson: string }> = [];\n public Disposed = false;\n public BoundSurface: FakeSurface | null = null;\n\n public get ChannelName(): string {\n return 'Echo';\n }\n public get ToolNamePrefix(): string {\n return 'Echo.';\n }\n public get TabTitle(): string {\n return 'Echo';\n }\n public get TabIcon(): string {\n return 'fa-solid fa-microphone';\n }\n public GetToolDefinitions(): RealtimeToolDefinition[] {\n return [\n { Name: 'Echo.Say', Description: 'Echo a phrase', ParametersSchema: { type: 'object' } },\n { Name: 'Echo.Clear', Description: 'Clear echoes', ParametersSchema: { type: 'object' } }\n ];\n }\n public GetSurfaceComponent(): import('@angular/core').Type<FakeSurface> {\n return FakeSurface;\n }\n public BindSurface(instance: FakeSurface): void {\n this.BoundSurface = instance;\n }\n public ApplyAgentTool(toolName: string, argsJson: string): string {\n this.AppliedCalls.push({ ToolName: toolName, ArgsJson: argsJson });\n return JSON.stringify({ success: true, echoed: toolName });\n }\n public override Dispose(): void {\n this.Disposed = true;\n super.Dispose();\n }\n\n /** Test seam: expose the host context the service handed us. */\n public get Ctx(): RealtimeChannelContext | null {\n return this.Context;\n }\n}\n\n/**\n * Stubs the provider-scoped AIEngineBase whose cached `AgentChannels` the service reads\n * (rows default to ACTIVE; pass `IsActive: false` to exercise the active-only filter).\n * `success = false` makes the engine load reject — the registry-failure degradation path.\n */\nfunction mockChannelRegistry(\n rows: Array<{ ID: string; Name: string; ClientPluginClass: string; IsActive?: boolean }>,\n success = true\n): ReturnType<typeof vi.fn> {\n const configFn = vi.fn(async () => {\n if (!success) {\n throw new Error('boom');\n }\n });\n const fakeEngine = {\n Config: configFn,\n get AgentChannels() {\n return rows.map(r => ({ IsActive: true, ...r }));\n }\n };\n vi.spyOn(AIEngineBase, 'GetProviderInstance').mockReturnValue(fakeEngine as unknown as AIEngineBase);\n return configFn;\n}\n\ndescribe('RealtimeSessionService — interactive-channel registry resolution', () => {\n let service: RealtimeSessionService;\n\n beforeEach(() => {\n service = new RealtimeSessionService();\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n it('resolves ACTIVE registry rows into per-session plugin instances via the ClassFactory', async () => {\n const configFn = mockChannelRegistry([\n { ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' },\n // Inactive rows never become session plugins (parity with the old `IsActive = 1` filter).\n { ID: 'c2', Name: 'Dormant', ClientPluginClass: 'TestEchoChannel', IsActive: false }\n ]);\n\n await internals(service).startChannels();\n\n // Lazily configures the provider-scoped engine before reading the cached registry.\n expect(configFn).toHaveBeenCalledWith(false, undefined, service.Provider);\n expect(service.ActiveChannels).toHaveLength(1);\n expect(service.ActiveChannels[0]).toBeInstanceOf(TestEchoChannel);\n });\n\n it('creates a FRESH instance per session (plugins are not singletons)', async () => {\n mockChannelRegistry([{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }]);\n await internals(service).startChannels();\n const first = service.ActiveChannels[0];\n\n await internals(service).startChannels();\n expect(service.ActiveChannels[0]).not.toBe(first);\n });\n\n it('skips rows whose ClientPluginClass has no registration (logged, never fatal)', async () => {\n const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);\n mockChannelRegistry([\n { ID: 'c1', Name: 'Ghost', ClientPluginClass: 'NoSuchChannelPlugin' },\n { ID: 'c2', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }\n ]);\n\n await internals(service).startChannels();\n\n expect(service.ActiveChannels).toHaveLength(1);\n expect(service.ActiveChannels[0]).toBeInstanceOf(TestEchoChannel);\n expect(warn).toHaveBeenCalledWith(expect.stringContaining(\"No client plugin registered for channel 'Ghost'\"));\n });\n\n it('degrades to NO channels when the registry load fails (the voice session must proceed)', async () => {\n vi.spyOn(console, 'warn').mockImplementation(() => undefined);\n mockChannelRegistry([], false);\n\n const tools = await internals(service).startChannels();\n\n expect(tools).toEqual([]);\n expect(service.ActiveChannels).toEqual([]);\n });\n\n it('degrades to NO channels when the engine acquisition throws', async () => {\n vi.spyOn(console, 'warn').mockImplementation(() => undefined);\n vi.spyOn(AIEngineBase, 'GetProviderInstance').mockImplementation(() => {\n throw new Error('no provider');\n });\n\n const tools = await internals(service).startChannels();\n\n expect(tools).toEqual([]);\n expect(service.ActiveChannels).toEqual([]);\n });\n\n it('aggregates every plugin tool definition into the clientTools set for the mint', async () => {\n mockChannelRegistry([{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }]);\n\n const tools = await internals(service).startChannels();\n\n expect(tools.map(t => t.Name)).toEqual(['Echo.Say', 'Echo.Clear']);\n });\n\n it('emits the resolved plugins on ActiveChannels$ (the overlay registers tabs from it)', async () => {\n mockChannelRegistry([{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }]);\n const emissions: number[] = [];\n const sub = service.ActiveChannels$.subscribe(channels => emissions.push(channels.length));\n\n await internals(service).startChannels();\n\n sub.unsubscribe();\n expect(emissions).toEqual([0, 1]); // BehaviorSubject replay, then the resolved set\n });\n});\n\ndescribe('RealtimeSessionService — per-plugin tool routing + host context', () => {\n let service: RealtimeSessionService;\n let fakeClient: FakeRealtimeClient;\n let plugin: TestEchoChannel;\n\n beforeEach(async () => {\n service = new RealtimeSessionService();\n fakeClient = new FakeRealtimeClient();\n internals(service).client = fakeClient;\n mockChannelRegistry([{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }]);\n await internals(service).startChannels();\n plugin = service.ActiveChannels[0] as TestEchoChannel;\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n });\n\n it('routes prefix-matched tool calls to the plugin and feeds its result back to the model', async () => {\n await internals(service).handleToolCall({ CallID: 'call-1', ToolName: 'Echo.Say', ArgumentsJson: '{\"phrase\":\"hi\"}' });\n\n expect(plugin.AppliedCalls).toEqual([{ ToolName: 'Echo.Say', ArgsJson: '{\"phrase\":\"hi\"}' }]);\n expect(fakeClient.ToolResults).toEqual([\n { CallID: 'call-1', ResultJson: JSON.stringify({ success: true, echoed: 'Echo.Say' }) }\n ]);\n });\n\n it('hands each plugin a context whose AgentName matches the session agent', () => {\n expect(plugin.Ctx?.AgentName).toBe(service.CurrentAgentName);\n });\n\n it('SetFocusMode rides ChannelFocus$ tagged with the requesting plugin', () => {\n const events: RealtimeChannelFocusEvent[] = [];\n const sub = service.ChannelFocus$.subscribe(e => events.push(e));\n\n plugin.Ctx?.SetFocusMode(true);\n plugin.Ctx?.SetFocusMode(false);\n\n sub.unsubscribe();\n expect(events).toEqual([\n { Channel: plugin, Focused: true },\n { Channel: plugin, Focused: false }\n ]);\n });\n});\n\ndescribe('RealtimeSessionService — debounced channel saves + teardown flush/dispose', () => {\n let service: RealtimeSessionService;\n let plugin: TestEchoChannel;\n let saveSpy: MockInstance<RealtimeSessionService['SaveChannelState']>;\n\n beforeEach(async () => {\n vi.useFakeTimers();\n service = new RealtimeSessionService();\n internals(service).agentSessionId = 'session-123';\n saveSpy = vi.spyOn(service, 'SaveChannelState').mockResolvedValue(true);\n mockChannelRegistry([{ ID: 'c1', Name: 'Echo', ClientPluginClass: 'TestEchoChannel' }]);\n await internals(service).startChannels();\n plugin = service.ActiveChannels[0] as TestEchoChannel;\n });\n\n afterEach(() => {\n vi.useRealTimers();\n vi.restoreAllMocks();\n });\n\n it('debounces RequestSave: a change burst becomes ONE save with the LATEST state', () => {\n plugin.Ctx?.RequestSave('{\"v\":1}');\n plugin.Ctx?.RequestSave('{\"v\":2}');\n plugin.Ctx?.RequestSave('{\"v\":3}');\n expect(saveSpy).not.toHaveBeenCalled();\n\n vi.advanceTimersByTime(3000);\n\n expect(saveSpy).toHaveBeenCalledTimes(1);\n expect(saveSpy).toHaveBeenCalledWith('Echo', '{\"v\":3}', 'session-123');\n });\n\n it('teardown FLUSHES a pending save immediately (captured session id) and disposes plugins', async () => {\n plugin.Ctx?.RequestSave('{\"final\":true}');\n\n await internals(service).teardown(false);\n\n expect(saveSpy).toHaveBeenCalledTimes(1);\n expect(saveSpy).toHaveBeenCalledWith('Echo', '{\"final\":true}', 'session-123');\n expect(plugin.Disposed).toBe(true);\n expect(service.ActiveChannels).toEqual([]);\n });\n\n it('teardown with nothing pending saves nothing but still disposes', async () => {\n await internals(service).teardown(false);\n\n expect(saveSpy).not.toHaveBeenCalled();\n expect(plugin.Disposed).toBe(true);\n });\n\n it('a Dispose error in one plugin is contained (teardown completes)', async () => {\n const error = vi.spyOn(console, 'error').mockImplementation(() => undefined);\n vi.spyOn(plugin, 'Dispose').mockImplementation(() => {\n throw new Error('plugin exploded');\n });\n\n await internals(service).teardown(false);\n\n expect(service.ActiveChannels).toEqual([]);\n expect(error).toHaveBeenCalledWith(expect.stringContaining(\"Channel 'Echo' Dispose failed\"), expect.any(Error));\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-session-client-tools.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/realtime-session-client-tools.test.ts"],"names":[],"mappings":""}
|