@memberjunction/ng-conversations 6.2.0-edge.0 → 6.2.0-edge.1
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 +35 -2
- package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts +19 -3
- 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 +39 -7
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js.map +1 -1
- package/dist/lib/components/agent/active-agent-indicator.component.d.ts +74 -6
- package/dist/lib/components/agent/active-agent-indicator.component.d.ts.map +1 -1
- package/dist/lib/components/agent/active-agent-indicator.component.js +111 -21
- package/dist/lib/components/agent/active-agent-indicator.component.js.map +1 -1
- package/dist/lib/components/agent/agent-process-panel.component.d.ts +31 -5
- package/dist/lib/components/agent/agent-process-panel.component.d.ts.map +1 -1
- package/dist/lib/components/agent/agent-process-panel.component.js +71 -15
- package/dist/lib/components/agent/agent-process-panel.component.js.map +1 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.d.ts +65 -9
- package/dist/lib/components/artifact/artifact-share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/artifact/artifact-share-modal.component.js +169 -57
- package/dist/lib/components/artifact/artifact-share-modal.component.js.map +1 -1
- package/dist/lib/components/attachment/image-viewer.component.d.ts +77 -11
- package/dist/lib/components/attachment/image-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/attachment/image-viewer.component.js +181 -47
- package/dist/lib/components/attachment/image-viewer.component.js.map +1 -1
- package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts +129 -19
- package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/artifact-collection-picker-modal.component.js +350 -116
- package/dist/lib/components/collection/artifact-collection-picker-modal.component.js.map +1 -1
- package/dist/lib/components/collection/artifact-create-modal.component.d.ts +60 -8
- package/dist/lib/components/collection/artifact-create-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/artifact-create-modal.component.js +130 -46
- package/dist/lib/components/collection/artifact-create-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-artifact-card.component.d.ts +63 -3
- package/dist/lib/components/collection/collection-artifact-card.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-artifact-card.component.js +113 -19
- package/dist/lib/components/collection/collection-artifact-card.component.js.map +1 -1
- package/dist/lib/components/collection/collection-form-modal.component.d.ts +54 -8
- package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-form-modal.component.js +130 -46
- package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-share-modal.component.d.ts +70 -10
- package/dist/lib/components/collection/collection-share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-share-modal.component.js +175 -53
- package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-tree.component.d.ts +89 -9
- package/dist/lib/components/collection/collection-tree.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-tree.component.js +220 -70
- package/dist/lib/components/collection/collection-tree.component.js.map +1 -1
- package/dist/lib/components/collection/collection-view.component.d.ts +89 -11
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-view.component.js +154 -40
- package/dist/lib/components/collection/collection-view.component.js.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.d.ts +390 -38
- package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.js +951 -367
- package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.d.ts +213 -18
- package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.js +388 -44
- package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts +12 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.js +26 -4
- package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +1090 -123
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +2399 -706
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.d.ts +139 -19
- package/dist/lib/components/conversation/conversation-empty-state.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-empty-state.component.js +296 -59
- package/dist/lib/components/conversation/conversation-empty-state.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.d.ts +579 -78
- package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.js +2322 -823
- package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts +40 -4
- package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/pinned-messages-panel.component.js +72 -14
- package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
- package/dist/lib/components/dialogs/input-dialog.component.d.ts +57 -11
- package/dist/lib/components/dialogs/input-dialog.component.d.ts.map +1 -1
- package/dist/lib/components/dialogs/input-dialog.component.js +128 -16
- package/dist/lib/components/dialogs/input-dialog.component.js.map +1 -1
- package/dist/lib/components/dialogs/rating-dialog.component.d.ts +68 -10
- package/dist/lib/components/dialogs/rating-dialog.component.d.ts.map +1 -1
- package/dist/lib/components/dialogs/rating-dialog.component.js +151 -27
- package/dist/lib/components/dialogs/rating-dialog.component.js.map +1 -1
- package/dist/lib/components/export/export-modal.component.d.ts +84 -10
- package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
- package/dist/lib/components/export/export-modal.component.js +173 -49
- package/dist/lib/components/export/export-modal.component.js.map +1 -1
- package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts +29 -3
- package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts.map +1 -1
- package/dist/lib/components/global-tasks/global-tasks-panel.component.js +58 -12
- package/dist/lib/components/global-tasks/global-tasks-panel.component.js.map +1 -1
- package/dist/lib/components/library/library-full-view.component.d.ts +57 -8
- package/dist/lib/components/library/library-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/library/library-full-view.component.js +119 -35
- package/dist/lib/components/library/library-full-view.component.js.map +1 -1
- package/dist/lib/components/members/members-modal.component.d.ts +76 -10
- package/dist/lib/components/members/members-modal.component.d.ts.map +1 -1
- package/dist/lib/components/members/members-modal.component.js +164 -50
- package/dist/lib/components/members/members-modal.component.js.map +1 -1
- package/dist/lib/components/message/actionable-commands.component.d.ts +37 -5
- package/dist/lib/components/message/actionable-commands.component.d.ts.map +1 -1
- package/dist/lib/components/message/actionable-commands.component.js +82 -16
- package/dist/lib/components/message/actionable-commands.component.js.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.d.ts +46 -10
- package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.js +120 -36
- package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +549 -74
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +1250 -421
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +411 -29
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +896 -222
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +288 -29
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +561 -123
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/navigation/conversation-navigation.component.d.ts +64 -5
- package/dist/lib/components/navigation/conversation-navigation.component.d.ts.map +1 -1
- package/dist/lib/components/navigation/conversation-navigation.component.js +101 -11
- package/dist/lib/components/navigation/conversation-navigation.component.js.map +1 -1
- package/dist/lib/components/notification/activity-indicator.component.d.ts +6 -2
- package/dist/lib/components/notification/activity-indicator.component.d.ts.map +1 -1
- package/dist/lib/components/notification/activity-indicator.component.js +13 -3
- package/dist/lib/components/notification/activity-indicator.component.js.map +1 -1
- package/dist/lib/components/notification/notification-badge.component.d.ts +15 -3
- package/dist/lib/components/notification/notification-badge.component.d.ts.map +1 -1
- package/dist/lib/components/notification/notification-badge.component.js +36 -8
- package/dist/lib/components/notification/notification-badge.component.js.map +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.d.ts +1 -1
- package/dist/lib/components/overlay/chat-overlay.component.js +4 -4
- package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
- package/dist/lib/components/project/project-form-modal.component.d.ts +93 -11
- package/dist/lib/components/project/project-form-modal.component.d.ts.map +1 -1
- package/dist/lib/components/project/project-form-modal.component.js +348 -87
- package/dist/lib/components/project/project-form-modal.component.js.map +1 -1
- package/dist/lib/components/project/project-selector.component.d.ts +78 -8
- package/dist/lib/components/project/project-selector.component.d.ts.map +1 -1
- package/dist/lib/components/project/project-selector.component.js +177 -46
- package/dist/lib/components/project/project-selector.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +1 -1
- package/dist/lib/components/realtime/realtime-activity-rail.component.js +2 -2
- package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +1 -1
- package/dist/lib/components/realtime/realtime-delegation-card.component.js +2 -2
- package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +2 -2
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +18 -18
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts +47 -23
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.js +136 -92
- package/dist/lib/components/realtime/realtime-session-timeline-card.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +2 -2
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js +4 -4
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js +3 -3
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.d.ts +13 -11
- package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.js +29 -25
- package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +3 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +6 -2
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
- package/dist/lib/components/search/search-panel.component.d.ts +133 -22
- package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
- package/dist/lib/components/search/search-panel.component.js +312 -83
- package/dist/lib/components/search/search-panel.component.js.map +1 -1
- package/dist/lib/components/share/share-modal.component.d.ts +69 -9
- package/dist/lib/components/share/share-modal.component.d.ts.map +1 -1
- package/dist/lib/components/share/share-modal.component.js +139 -31
- package/dist/lib/components/share/share-modal.component.js.map +1 -1
- package/dist/lib/components/shared/user-picker.component.d.ts +48 -8
- package/dist/lib/components/shared/user-picker.component.d.ts.map +1 -1
- package/dist/lib/components/shared/user-picker.component.js +110 -30
- package/dist/lib/components/shared/user-picker.component.js.map +1 -1
- package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts +114 -11
- package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts.map +1 -1
- package/dist/lib/components/sidebar/conversation-sidebar.component.js +199 -21
- package/dist/lib/components/sidebar/conversation-sidebar.component.js.map +1 -1
- package/dist/lib/components/sidebar/routines-section.component.d.ts +20 -1
- package/dist/lib/components/sidebar/routines-section.component.d.ts.map +1 -1
- package/dist/lib/components/sidebar/routines-section.component.js +25 -5
- package/dist/lib/components/sidebar/routines-section.component.js.map +1 -1
- package/dist/lib/components/slots/slot-interfaces.d.ts +19 -0
- package/dist/lib/components/slots/slot-interfaces.d.ts.map +1 -1
- package/dist/lib/components/slots/slot-interfaces.js.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.d.ts +95 -13
- package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.js +223 -75
- package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
- package/dist/lib/components/tasks/task-widget.component.d.ts +46 -6
- package/dist/lib/components/tasks/task-widget.component.d.ts.map +1 -1
- package/dist/lib/components/tasks/task-widget.component.js +100 -16
- package/dist/lib/components/tasks/task-widget.component.js.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +64 -7
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js +127 -27
- package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
- package/dist/lib/components/thread/thread-panel.component.d.ts +66 -8
- package/dist/lib/components/thread/thread-panel.component.d.ts.map +1 -1
- package/dist/lib/components/thread/thread-panel.component.js +146 -36
- package/dist/lib/components/thread/thread-panel.component.js.map +1 -1
- package/dist/lib/components/toast/toast.component.d.ts +11 -1
- package/dist/lib/components/toast/toast.component.d.ts.map +1 -1
- package/dist/lib/components/toast/toast.component.js +25 -5
- package/dist/lib/components/toast/toast.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +385 -42
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +887 -291
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts +8 -0
- package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts.map +1 -1
- package/dist/lib/composer-plugins/base-conversation-mention.provider.js +8 -1
- package/dist/lib/composer-plugins/base-conversation-mention.provider.js.map +1 -1
- package/dist/lib/directives/chat-slot.directive.d.ts +5 -1
- package/dist/lib/directives/chat-slot.directive.d.ts.map +1 -1
- package/dist/lib/directives/chat-slot.directive.js.map +1 -1
- package/dist/lib/directives/search-shortcut.directive.d.ts +9 -1
- package/dist/lib/directives/search-shortcut.directive.d.ts.map +1 -1
- package/dist/lib/directives/search-shortcut.directive.js +14 -4
- package/dist/lib/directives/search-shortcut.directive.js.map +1 -1
- package/dist/lib/events/chat-events.d.ts +34 -7
- package/dist/lib/events/chat-events.d.ts.map +1 -1
- package/dist/lib/events/chat-events.js +37 -7
- package/dist/lib/events/chat-events.js.map +1 -1
- package/dist/lib/models/agent-turn.model.d.ts +103 -0
- package/dist/lib/models/agent-turn.model.d.ts.map +1 -0
- package/dist/lib/models/agent-turn.model.js +12 -0
- package/dist/lib/models/agent-turn.model.js.map +1 -0
- package/dist/lib/models/collection-view.model.js.map +1 -1
- package/dist/lib/models/conversation-state.model.d.ts +8 -0
- 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/models/lazy-artifact-info.d.ts +44 -12
- package/dist/lib/models/lazy-artifact-info.d.ts.map +1 -1
- package/dist/lib/models/lazy-artifact-info.js +98 -34
- package/dist/lib/models/lazy-artifact-info.js.map +1 -1
- package/dist/lib/services/active-tasks.service.d.ts +30 -4
- package/dist/lib/services/active-tasks.service.d.ts.map +1 -1
- package/dist/lib/services/active-tasks.service.js +71 -19
- package/dist/lib/services/active-tasks.service.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts +17 -1
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +48 -16
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/artifact-permission.service.d.ts +39 -0
- package/dist/lib/services/artifact-permission.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-permission.service.js +152 -17
- package/dist/lib/services/artifact-permission.service.js.map +1 -1
- package/dist/lib/services/artifact-state.service.d.ts +58 -5
- package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-state.service.js +135 -35
- package/dist/lib/services/artifact-state.service.js.map +1 -1
- package/dist/lib/services/collection-permission.service.d.ts +28 -0
- package/dist/lib/services/collection-permission.service.d.ts.map +1 -1
- package/dist/lib/services/collection-permission.service.js +88 -32
- package/dist/lib/services/collection-permission.service.js.map +1 -1
- package/dist/lib/services/collection-state.service.d.ts +11 -1
- package/dist/lib/services/collection-state.service.d.ts.map +1 -1
- package/dist/lib/services/collection-state.service.js +25 -5
- package/dist/lib/services/collection-state.service.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +26 -4
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +57 -18
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-attachment.service.d.ts +17 -0
- package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-attachment.service.js +38 -10
- package/dist/lib/services/conversation-attachment.service.js.map +1 -1
- package/dist/lib/services/conversation-streaming.service.d.ts +22 -0
- package/dist/lib/services/conversation-streaming.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-streaming.service.js +50 -10
- package/dist/lib/services/conversation-streaming.service.js.map +1 -1
- package/dist/lib/services/data-cache.service.d.ts +31 -0
- package/dist/lib/services/data-cache.service.d.ts.map +1 -1
- package/dist/lib/services/data-cache.service.js +71 -15
- package/dist/lib/services/data-cache.service.js.map +1 -1
- package/dist/lib/services/dialog.service.d.ts +13 -0
- package/dist/lib/services/dialog.service.d.ts.map +1 -1
- package/dist/lib/services/dialog.service.js +25 -5
- package/dist/lib/services/dialog.service.js.map +1 -1
- package/dist/lib/services/export.service.d.ts +2 -0
- package/dist/lib/services/export.service.d.ts.map +1 -1
- package/dist/lib/services/export.service.js +5 -1
- package/dist/lib/services/export.service.js.map +1 -1
- package/dist/lib/services/mention-parser.service.d.ts +10 -0
- package/dist/lib/services/mention-parser.service.d.ts.map +1 -1
- package/dist/lib/services/mention-parser.service.js +25 -5
- package/dist/lib/services/mention-parser.service.js.map +1 -1
- package/dist/lib/services/notification.service.d.ts +54 -6
- package/dist/lib/services/notification.service.d.ts.map +1 -1
- package/dist/lib/services/notification.service.js +123 -27
- package/dist/lib/services/notification.service.js.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.d.ts +4 -4
- package/dist/lib/services/realtime-audio-recorder.js +12 -12
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
- package/dist/lib/services/realtime-pcm-wav.d.ts +4 -0
- package/dist/lib/services/realtime-pcm-wav.d.ts.map +1 -1
- package/dist/lib/services/realtime-pcm-wav.js +10 -2
- package/dist/lib/services/realtime-pcm-wav.js.map +1 -1
- package/dist/lib/services/search.service.d.ts +42 -9
- package/dist/lib/services/search.service.d.ts.map +1 -1
- package/dist/lib/services/search.service.js +103 -23
- package/dist/lib/services/search.service.js.map +1 -1
- package/dist/lib/services/toast.service.d.ts +19 -1
- package/dist/lib/services/toast.service.d.ts.map +1 -1
- package/dist/lib/services/toast.service.js +45 -9
- package/dist/lib/services/toast.service.js.map +1 -1
- package/dist/lib/services/ui-command-handler.service.d.ts +16 -2
- package/dist/lib/services/ui-command-handler.service.d.ts.map +1 -1
- package/dist/lib/services/ui-command-handler.service.js +36 -8
- package/dist/lib/services/ui-command-handler.service.js.map +1 -1
- package/dist/lib/utils/agent-artifact-summary.d.ts +2 -2
- package/dist/lib/utils/agent-artifact-summary.js +3 -3
- package/dist/lib/utils/agent-artifact-summary.js.map +1 -1
- package/dist/lib/utils/agent-turn-routing.d.ts +69 -0
- package/dist/lib/utils/agent-turn-routing.d.ts.map +1 -0
- package/dist/lib/utils/agent-turn-routing.js +96 -0
- package/dist/lib/utils/agent-turn-routing.js.map +1 -0
- package/dist/lib/utils/artifact-panel-action.d.ts +15 -4
- package/dist/lib/utils/artifact-panel-action.d.ts.map +1 -1
- package/dist/lib/utils/artifact-panel-action.js +10 -2
- package/dist/lib/utils/artifact-panel-action.js.map +1 -1
- package/dist/lib/utils/distinct-artifacts.d.ts +2 -0
- package/dist/lib/utils/distinct-artifacts.d.ts.map +1 -1
- package/dist/lib/utils/distinct-artifacts.js +5 -1
- package/dist/lib/utils/distinct-artifacts.js.map +1 -1
- package/dist/lib/utils/plan-mode-preference.d.ts +2 -2
- package/dist/lib/utils/plan-mode-preference.js +6 -6
- package/dist/lib/utils/plan-mode-preference.js.map +1 -1
- package/dist/public-api.d.ts +3 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +3 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +32 -32
|
@@ -3,6 +3,7 @@ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
|
3
3
|
import { LogStatusEx } from '@memberjunction/core';
|
|
4
4
|
import { MJEnvironmentEntityExtended, ConversationEngine, UserInfoEngine, TaskGraphSubmitOperation } from '@memberjunction/core-entities';
|
|
5
5
|
import { BeforeAgentTurnEventArgs, AfterAgentTurnEventArgs } from '../../events/chat-events';
|
|
6
|
+
import { ResolveAgentTurn, IsAgentAllowed, FindDisallowedTaskGraphAgents } from '../../utils/agent-turn-routing';
|
|
6
7
|
import { GenerateAndApplyConversationName } from '../../services/conversation-naming';
|
|
7
8
|
import { AIEngineBase } from '@memberjunction/ai-engine-base';
|
|
8
9
|
import { ConversationUtility, agentFailureDisposition, agentFailureMessage } from '@memberjunction/ai-core-plus';
|
|
@@ -59,30 +60,198 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
59
60
|
realtimeSession;
|
|
60
61
|
// Default artifact type ID for JSON (when agent doesn't specify DefaultArtifactTypeID)
|
|
61
62
|
JSON_ARTIFACT_TYPE_ID = 'ae674c7e-ea0d-49ea-89e4-0649f5eb20d4';
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
ConversationId;
|
|
64
|
+
/** @deprecated Use {@link ConversationId}. */
|
|
65
|
+
set conversationId(value) {
|
|
66
|
+
this.ConversationId = value;
|
|
67
|
+
}
|
|
68
|
+
/** @deprecated Use {@link ConversationId}. */
|
|
69
|
+
get conversationId() {
|
|
70
|
+
return this.ConversationId;
|
|
71
|
+
}
|
|
72
|
+
ConversationName;
|
|
73
|
+
/** @deprecated Use {@link ConversationName}. */
|
|
74
|
+
set conversationName(value) {
|
|
75
|
+
this.ConversationName = value;
|
|
76
|
+
}
|
|
77
|
+
/** @deprecated Use {@link ConversationName}. */
|
|
78
|
+
get conversationName() {
|
|
79
|
+
return this.ConversationName;
|
|
80
|
+
} // For task tracking display
|
|
81
|
+
CurrentUser;
|
|
82
|
+
/** @deprecated Use {@link CurrentUser}. */
|
|
83
|
+
set currentUser(value) {
|
|
84
|
+
this.CurrentUser = value;
|
|
85
|
+
}
|
|
86
|
+
/** @deprecated Use {@link CurrentUser}. */
|
|
87
|
+
get currentUser() {
|
|
88
|
+
return this.CurrentUser;
|
|
89
|
+
}
|
|
90
|
+
Disabled = false;
|
|
91
|
+
/** @deprecated Use {@link Disabled}. */
|
|
92
|
+
set disabled(value) {
|
|
93
|
+
this.Disabled = value;
|
|
94
|
+
}
|
|
95
|
+
/** @deprecated Use {@link Disabled}. */
|
|
96
|
+
get disabled() {
|
|
97
|
+
return this.Disabled;
|
|
98
|
+
}
|
|
99
|
+
Placeholder = 'Type a message... (Ctrl+Enter to send)';
|
|
100
|
+
/** @deprecated Use {@link Placeholder}. */
|
|
101
|
+
set placeholder(value) {
|
|
102
|
+
this.Placeholder = value;
|
|
103
|
+
}
|
|
104
|
+
/** @deprecated Use {@link Placeholder}. */
|
|
105
|
+
get placeholder() {
|
|
106
|
+
return this.Placeholder;
|
|
107
|
+
}
|
|
108
|
+
ParentMessageId;
|
|
109
|
+
/** @deprecated Use {@link ParentMessageId}. */
|
|
110
|
+
set parentMessageId(value) {
|
|
111
|
+
this.ParentMessageId = value;
|
|
112
|
+
}
|
|
113
|
+
/** @deprecated Use {@link ParentMessageId}. */
|
|
114
|
+
get parentMessageId() {
|
|
115
|
+
return this.ParentMessageId;
|
|
116
|
+
} // Optional: for replying in threads
|
|
117
|
+
EnableAttachments = true;
|
|
118
|
+
/** @deprecated Use {@link EnableAttachments}. */
|
|
119
|
+
set enableAttachments(value) {
|
|
120
|
+
this.EnableAttachments = value;
|
|
121
|
+
}
|
|
122
|
+
/** @deprecated Use {@link EnableAttachments}. */
|
|
123
|
+
get enableAttachments() {
|
|
124
|
+
return this.EnableAttachments;
|
|
125
|
+
} // Whether to show attachment button (based on agent modality support)
|
|
126
|
+
EnableMentions = true;
|
|
127
|
+
/** @deprecated Use {@link EnableMentions}. */
|
|
128
|
+
set enableMentions(value) {
|
|
129
|
+
this.EnableMentions = value;
|
|
130
|
+
}
|
|
131
|
+
/** @deprecated Use {@link EnableMentions}. */
|
|
132
|
+
get enableMentions() {
|
|
133
|
+
return this.EnableMentions;
|
|
134
|
+
} // Whether to enable @-mention autocomplete (agents/users). Hosts addressing a single fixed agent (e.g. Form Builder cockpit) typically set false.
|
|
70
135
|
// Per-type caps under enableMentions (all default true) — forwarded to the AI composer's
|
|
71
136
|
// EnableAgentMentions/EnableEntityMentions/EnableSkillCommands. Let a host keep '/' skill
|
|
72
137
|
// commands while dropping '@' agent mentions (which would override a pinned default agent).
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
138
|
+
EnableAgentMentions = true;
|
|
139
|
+
/** @deprecated Use {@link EnableAgentMentions}. */
|
|
140
|
+
set enableAgentMentions(value) {
|
|
141
|
+
this.EnableAgentMentions = value;
|
|
142
|
+
}
|
|
143
|
+
/** @deprecated Use {@link EnableAgentMentions}. */
|
|
144
|
+
get enableAgentMentions() {
|
|
145
|
+
return this.EnableAgentMentions;
|
|
146
|
+
}
|
|
147
|
+
EnableEntityMentions = true;
|
|
148
|
+
/** @deprecated Use {@link EnableEntityMentions}. */
|
|
149
|
+
set enableEntityMentions(value) {
|
|
150
|
+
this.EnableEntityMentions = value;
|
|
151
|
+
}
|
|
152
|
+
/** @deprecated Use {@link EnableEntityMentions}. */
|
|
153
|
+
get enableEntityMentions() {
|
|
154
|
+
return this.EnableEntityMentions;
|
|
155
|
+
}
|
|
156
|
+
EnableSkillCommands = true;
|
|
157
|
+
/** @deprecated Use {@link EnableSkillCommands}. */
|
|
158
|
+
set enableSkillCommands(value) {
|
|
159
|
+
this.EnableSkillCommands = value;
|
|
160
|
+
}
|
|
161
|
+
/** @deprecated Use {@link EnableSkillCommands}. */
|
|
162
|
+
get enableSkillCommands() {
|
|
163
|
+
return this.EnableSkillCommands;
|
|
164
|
+
}
|
|
165
|
+
EnablePlanMode = true;
|
|
166
|
+
/** @deprecated Use {@link EnablePlanMode}. */
|
|
167
|
+
set enablePlanMode(value) {
|
|
168
|
+
this.EnablePlanMode = value;
|
|
169
|
+
}
|
|
170
|
+
/** @deprecated Use {@link EnablePlanMode}. */
|
|
171
|
+
get enablePlanMode() {
|
|
172
|
+
return this.EnablePlanMode;
|
|
173
|
+
} // Whether the composer shows the Plan Mode toggle. Hosts that don't expose plan-mode workflows set false.
|
|
174
|
+
EnableRealtime = true;
|
|
175
|
+
/** @deprecated Use {@link EnableRealtime}. */
|
|
176
|
+
set enableRealtime(value) {
|
|
177
|
+
this.EnableRealtime = value;
|
|
178
|
+
}
|
|
179
|
+
/** @deprecated Use {@link EnableRealtime}. */
|
|
180
|
+
get enableRealtime() {
|
|
181
|
+
return this.EnableRealtime;
|
|
182
|
+
} // Whether the composer shows the realtime voice-call launcher/options. Hosts without a voice experience set false.
|
|
183
|
+
MaxAttachments = 10;
|
|
184
|
+
/** @deprecated Use {@link MaxAttachments}. */
|
|
185
|
+
set maxAttachments(value) {
|
|
186
|
+
this.MaxAttachments = value;
|
|
187
|
+
}
|
|
188
|
+
/** @deprecated Use {@link MaxAttachments}. */
|
|
189
|
+
get maxAttachments() {
|
|
190
|
+
return this.MaxAttachments;
|
|
191
|
+
} // Maximum number of attachments per message
|
|
192
|
+
MaxAttachmentSizeBytes = 20 * 1024 * 1024;
|
|
193
|
+
/** @deprecated Use {@link MaxAttachmentSizeBytes}. */
|
|
194
|
+
set maxAttachmentSizeBytes(value) {
|
|
195
|
+
this.MaxAttachmentSizeBytes = value;
|
|
196
|
+
}
|
|
197
|
+
/** @deprecated Use {@link MaxAttachmentSizeBytes}. */
|
|
198
|
+
get maxAttachmentSizeBytes() {
|
|
199
|
+
return this.MaxAttachmentSizeBytes;
|
|
200
|
+
} // Maximum size per attachment (20MB default)
|
|
201
|
+
AcceptedFileTypes = 'image/*';
|
|
202
|
+
/** @deprecated Use {@link AcceptedFileTypes}. */
|
|
203
|
+
set acceptedFileTypes(value) {
|
|
204
|
+
this.AcceptedFileTypes = value;
|
|
205
|
+
}
|
|
206
|
+
/** @deprecated Use {@link AcceptedFileTypes}. */
|
|
207
|
+
get acceptedFileTypes() {
|
|
208
|
+
return this.AcceptedFileTypes;
|
|
209
|
+
} // Accepted MIME types pattern
|
|
210
|
+
ArtifactsByDetailId;
|
|
211
|
+
/** @deprecated Use {@link ArtifactsByDetailId}. */
|
|
212
|
+
set artifactsByDetailId(value) {
|
|
213
|
+
this.ArtifactsByDetailId = value;
|
|
214
|
+
}
|
|
215
|
+
/** @deprecated Use {@link ArtifactsByDetailId}. */
|
|
216
|
+
get artifactsByDetailId() {
|
|
217
|
+
return this.ArtifactsByDetailId;
|
|
218
|
+
} // Pre-loaded artifact data for performance
|
|
219
|
+
SystemArtifactsByDetailId;
|
|
220
|
+
/** @deprecated Use {@link SystemArtifactsByDetailId}. */
|
|
221
|
+
set systemArtifactsByDetailId(value) {
|
|
222
|
+
this.SystemArtifactsByDetailId = value;
|
|
223
|
+
}
|
|
224
|
+
/** @deprecated Use {@link SystemArtifactsByDetailId}. */
|
|
225
|
+
get systemArtifactsByDetailId() {
|
|
226
|
+
return this.SystemArtifactsByDetailId;
|
|
227
|
+
} // Pre-loaded system artifact data (Visibility='System Only')
|
|
228
|
+
AgentRunsByDetailId;
|
|
229
|
+
/** @deprecated Use {@link AgentRunsByDetailId}. */
|
|
230
|
+
set agentRunsByDetailId(value) {
|
|
231
|
+
this.AgentRunsByDetailId = value;
|
|
232
|
+
}
|
|
233
|
+
/** @deprecated Use {@link AgentRunsByDetailId}. */
|
|
234
|
+
get agentRunsByDetailId() {
|
|
235
|
+
return this.AgentRunsByDetailId;
|
|
236
|
+
} // Pre-loaded agent run data for performance
|
|
237
|
+
EmptyStateMode = false;
|
|
238
|
+
/** @deprecated Use {@link EmptyStateMode}. */
|
|
239
|
+
set emptyStateMode(value) {
|
|
240
|
+
this.EmptyStateMode = value;
|
|
241
|
+
}
|
|
242
|
+
/** @deprecated Use {@link EmptyStateMode}. */
|
|
243
|
+
get emptyStateMode() {
|
|
244
|
+
return this.EmptyStateMode;
|
|
245
|
+
} // When true, emits emptyStateSubmit instead of creating messages directly
|
|
246
|
+
AppContext = null;
|
|
247
|
+
/** @deprecated Use {@link AppContext}. */
|
|
248
|
+
set appContext(value) {
|
|
249
|
+
this.AppContext = value;
|
|
250
|
+
}
|
|
251
|
+
/** @deprecated Use {@link AppContext}. */
|
|
252
|
+
get appContext() {
|
|
253
|
+
return this.AppContext;
|
|
254
|
+
} // Application context for AI agent awareness
|
|
86
255
|
/**
|
|
87
256
|
* Plan Mode toggle state — sticky PER CONVERSATION, OFF by default (no behavior change unless
|
|
88
257
|
* the user turns it on). When on, the user's next message(s) in THIS conversation request Plan
|
|
@@ -99,7 +268,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
99
268
|
* conversation's flag OFF automatically (see message-item's plan-decision handling).
|
|
100
269
|
*/
|
|
101
270
|
get PlanModeEnabled() {
|
|
102
|
-
return PlanModePreference.IsEnabled(this.
|
|
271
|
+
return PlanModePreference.IsEnabled(this.ConversationId);
|
|
103
272
|
}
|
|
104
273
|
/**
|
|
105
274
|
* Skill IDs the user requested via `/skill-name` mentions in the message being routed. Collected
|
|
@@ -114,7 +283,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
114
283
|
* start of routing so the value is stable for the whole message dispatch.
|
|
115
284
|
*/
|
|
116
285
|
collectRequestedSkillIDs() {
|
|
117
|
-
const chipData = this.
|
|
286
|
+
const chipData = this.InputBox?.getMentionChipsData() || [];
|
|
118
287
|
return chipData.filter(chip => chip.type === 'skill').map(chip => chip.id);
|
|
119
288
|
}
|
|
120
289
|
/**
|
|
@@ -130,7 +299,15 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
130
299
|
* context and don't need Sage to route. Leave unset to preserve the
|
|
131
300
|
* standard Sage-fronted UX of the main Chat app.
|
|
132
301
|
*/
|
|
133
|
-
|
|
302
|
+
DefaultAgentId = null;
|
|
303
|
+
/** @deprecated Use {@link DefaultAgentId}. */
|
|
304
|
+
set defaultAgentId(value) {
|
|
305
|
+
this.DefaultAgentId = value;
|
|
306
|
+
}
|
|
307
|
+
/** @deprecated Use {@link DefaultAgentId}. */
|
|
308
|
+
get defaultAgentId() {
|
|
309
|
+
return this.DefaultAgentId;
|
|
310
|
+
}
|
|
134
311
|
/**
|
|
135
312
|
* Per-conversation pinned default agent — sourced from the loaded
|
|
136
313
|
* `MJConversationEntity.DefaultAgentID`. When set, this agent is used in
|
|
@@ -144,7 +321,15 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
144
321
|
* 4. defaultAgentId (embedder-supplied)
|
|
145
322
|
* 5. Sage fallback
|
|
146
323
|
*/
|
|
147
|
-
|
|
324
|
+
ConversationDefaultAgentId = null;
|
|
325
|
+
/** @deprecated Use {@link ConversationDefaultAgentId}. */
|
|
326
|
+
set conversationDefaultAgentId(value) {
|
|
327
|
+
this.ConversationDefaultAgentId = value;
|
|
328
|
+
}
|
|
329
|
+
/** @deprecated Use {@link ConversationDefaultAgentId}. */
|
|
330
|
+
get conversationDefaultAgentId() {
|
|
331
|
+
return this.ConversationDefaultAgentId;
|
|
332
|
+
}
|
|
148
333
|
/**
|
|
149
334
|
* The `MJ: AI Agent Configurations.ID` selected via the chat header's
|
|
150
335
|
* mode picker (Draft / Standard / High). Applied to **non-mention**
|
|
@@ -162,14 +347,22 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
162
347
|
* messages already in flight or already in history. Affects "what
|
|
163
348
|
* happens next."
|
|
164
349
|
*/
|
|
165
|
-
|
|
350
|
+
AgentConfigurationPresetId = null;
|
|
351
|
+
/** @deprecated Use {@link AgentConfigurationPresetId}. */
|
|
352
|
+
set agentConfigurationPresetId(value) {
|
|
353
|
+
this.AgentConfigurationPresetId = value;
|
|
354
|
+
}
|
|
355
|
+
/** @deprecated Use {@link AgentConfigurationPresetId}. */
|
|
356
|
+
get agentConfigurationPresetId() {
|
|
357
|
+
return this.AgentConfigurationPresetId;
|
|
358
|
+
}
|
|
166
359
|
// Initial message to send automatically - using getter/setter for precise control
|
|
167
360
|
_initialMessage = null;
|
|
168
361
|
_initialAttachments = null;
|
|
169
362
|
_isComponentReady = false; // Track if component is ready to send
|
|
170
363
|
/** Conversation this input has already auto-sent its pending first message for. */
|
|
171
364
|
_autoSentForConversationId = null;
|
|
172
|
-
set
|
|
365
|
+
set InitialMessage(value) {
|
|
173
366
|
// Handle case where an object with {text, attachments} is passed instead of just a string
|
|
174
367
|
// This can happen if there's a type mismatch in the binding chain
|
|
175
368
|
let actualValue = value;
|
|
@@ -183,31 +376,55 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
183
376
|
this.triggerInitialSend();
|
|
184
377
|
}
|
|
185
378
|
}
|
|
186
|
-
get
|
|
379
|
+
get InitialMessage() {
|
|
187
380
|
return this._initialMessage;
|
|
188
381
|
}
|
|
189
|
-
|
|
382
|
+
/** @deprecated Use {@link InitialMessage}. */
|
|
383
|
+
get initialMessage() {
|
|
384
|
+
return this.InitialMessage;
|
|
385
|
+
}
|
|
386
|
+
/** @deprecated Use {@link InitialMessage}. */
|
|
387
|
+
set initialMessage(value) {
|
|
388
|
+
this.InitialMessage = value;
|
|
389
|
+
}
|
|
390
|
+
set InitialAttachments(value) {
|
|
190
391
|
this._initialAttachments = value;
|
|
191
392
|
}
|
|
192
|
-
get
|
|
393
|
+
get InitialAttachments() {
|
|
193
394
|
return this._initialAttachments;
|
|
194
395
|
}
|
|
396
|
+
/** @deprecated Use {@link InitialAttachments}. */
|
|
397
|
+
get initialAttachments() {
|
|
398
|
+
return this.InitialAttachments;
|
|
399
|
+
}
|
|
400
|
+
/** @deprecated Use {@link InitialAttachments}. */
|
|
401
|
+
set initialAttachments(value) {
|
|
402
|
+
this.InitialAttachments = value;
|
|
403
|
+
}
|
|
195
404
|
_conversationHistory = [];
|
|
196
|
-
get
|
|
405
|
+
get ConversationHistory() {
|
|
197
406
|
return this._conversationHistory;
|
|
198
407
|
}
|
|
199
|
-
set
|
|
408
|
+
set ConversationHistory(value) {
|
|
200
409
|
this._conversationHistory = value;
|
|
201
410
|
}
|
|
411
|
+
/** @deprecated Use {@link ConversationHistory}. */
|
|
412
|
+
get conversationHistory() {
|
|
413
|
+
return this.ConversationHistory;
|
|
414
|
+
}
|
|
415
|
+
/** @deprecated Use {@link ConversationHistory}. */
|
|
416
|
+
set conversationHistory(value) {
|
|
417
|
+
this.ConversationHistory = value;
|
|
418
|
+
}
|
|
202
419
|
// Message IDs that are in-progress and need streaming reconnection
|
|
203
420
|
// Using getter/setter to react immediately when value changes (avoids timing issues with ngOnChanges)
|
|
204
421
|
_inProgressMessageIds;
|
|
205
|
-
set
|
|
422
|
+
set InProgressMessageIds(value) {
|
|
206
423
|
this._inProgressMessageIds = value;
|
|
207
424
|
// React immediately when input changes (after component initialized)
|
|
208
425
|
// This ensures callbacks are registered without relying on ngOnChanges timing
|
|
209
426
|
if (this.streamingService && value && value.length > 0) {
|
|
210
|
-
this.
|
|
427
|
+
this.ReconnectInProgressMessages();
|
|
211
428
|
}
|
|
212
429
|
else if (this.streamingService) {
|
|
213
430
|
// Empty/undefined — e.g. this input was backgrounded by a conversation swap
|
|
@@ -217,48 +434,236 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
217
434
|
this.unregisterAllCallbacks();
|
|
218
435
|
}
|
|
219
436
|
}
|
|
220
|
-
get
|
|
437
|
+
get InProgressMessageIds() {
|
|
221
438
|
return this._inProgressMessageIds;
|
|
222
439
|
}
|
|
440
|
+
/** @deprecated Use {@link InProgressMessageIds}. */
|
|
441
|
+
get inProgressMessageIds() {
|
|
442
|
+
return this.InProgressMessageIds;
|
|
443
|
+
}
|
|
444
|
+
/** @deprecated Use {@link InProgressMessageIds}. */
|
|
445
|
+
set inProgressMessageIds(value) {
|
|
446
|
+
this.InProgressMessageIds = value;
|
|
447
|
+
}
|
|
223
448
|
/**
|
|
224
449
|
* Application context for the current conversation. Threaded through from the
|
|
225
450
|
* chat-area component for inclusion in the {@link beforeAgentTurn} event payload —
|
|
226
451
|
* lets listeners reason about which app's chat surface is invoking the agent.
|
|
227
452
|
* Optional; defaults to null for surfaces with no app context.
|
|
228
453
|
*/
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
454
|
+
ApplicationId = null;
|
|
455
|
+
/** @deprecated Use {@link ApplicationId}. */
|
|
456
|
+
set applicationId(value) {
|
|
457
|
+
this.ApplicationId = value;
|
|
458
|
+
}
|
|
459
|
+
/** @deprecated Use {@link ApplicationId}. */
|
|
460
|
+
get applicationId() {
|
|
461
|
+
return this.ApplicationId;
|
|
462
|
+
}
|
|
463
|
+
// ── Host rules for agent turns ──────────────────────────────────────────
|
|
464
|
+
// All opt-in. Left at their defaults, every message is answered exactly as before.
|
|
465
|
+
/**
|
|
466
|
+
* When a message starts an agent turn. `'Always'` (the default) answers every message, as
|
|
467
|
+
* before. `'MentionOnly'` answers only a message that tags an agent; any other message is
|
|
468
|
+
* posted with no turn at all — no reply row, no placeholder, no turn events — which is what a
|
|
469
|
+
* chat between several people needs.
|
|
470
|
+
*/
|
|
471
|
+
AgentReplyMode = 'Always';
|
|
472
|
+
/**
|
|
473
|
+
* The agents that may answer here. Narrows the composer's '@' list, every route (a tagged
|
|
474
|
+
* agent, continuity, the pinned and host default agents, the conversation manager) and the
|
|
475
|
+
* conversation manager's delegation, including each agent step of a workflow it plans. A tagged
|
|
476
|
+
* agent outside the list is ignored. Null (the default) allows every agent the user can run;
|
|
477
|
+
* an empty list allows none.
|
|
478
|
+
*/
|
|
479
|
+
AllowedAgentIDs = null;
|
|
480
|
+
/**
|
|
481
|
+
* The people the composer's '@' list offers, such as the chat's members. Null (the default)
|
|
482
|
+
* offers only the current user, as before.
|
|
483
|
+
*/
|
|
484
|
+
MentionPeople = null;
|
|
232
485
|
/**
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
486
|
+
* The first moment of the conversation an agent turn may read. The server loads the agent's
|
|
487
|
+
* history from there and uses no summary of earlier messages; the run's own reads of the
|
|
488
|
+
* conversation (history tools, attached artifacts, the previous output it continues from)
|
|
489
|
+
* start there too, and so does the continuity route, which considers only replies written at
|
|
490
|
+
* or after it. Sent to the server only when set, so leaving it null keeps working against an
|
|
491
|
+
* MJAPI that predates it (one that predates it rejects a turn that sets it, rather than
|
|
492
|
+
* reading past the floor). Null (the default) reads the whole conversation.
|
|
238
493
|
*/
|
|
239
|
-
|
|
494
|
+
AgentHistoryFrom = null;
|
|
240
495
|
/**
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
* the
|
|
496
|
+
* Runs agent turns on the host's server instead of MJ's own path. The chat area still picks
|
|
497
|
+
* the agent and fires {@link BeforeAgentTurn}; it then calls the handler once per turn, before
|
|
498
|
+
* any reply row exists, and shows the rows the handler reports. Null (the default) runs turns
|
|
499
|
+
* on MJ's path.
|
|
244
500
|
*/
|
|
245
|
-
|
|
501
|
+
AgentTurnHandler = null;
|
|
502
|
+
/**
|
|
503
|
+
* Whether MJ names a new conversation from its first message. True (the default) keeps
|
|
504
|
+
* today's behavior; a host that names its own chats turns it off.
|
|
505
|
+
*/
|
|
506
|
+
AutoNameConversation = true;
|
|
507
|
+
MessageSent = new EventEmitter();
|
|
508
|
+
/**
|
|
509
|
+
* @deprecated Use {@link MessageSent}.
|
|
510
|
+
*
|
|
511
|
+
* The same emitter under the old binding name, so a template still binding
|
|
512
|
+
* (messageSent) keeps working. Must stay AFTER MessageSent: class fields
|
|
513
|
+
* initialise in order, and the other way round this captures undefined.
|
|
514
|
+
*/
|
|
515
|
+
messageSent = this.MessageSent;
|
|
516
|
+
AgentResponse = new EventEmitter();
|
|
517
|
+
/**
|
|
518
|
+
* @deprecated Use {@link AgentResponse}.
|
|
519
|
+
*
|
|
520
|
+
* The same emitter under the old binding name, so a template still binding
|
|
521
|
+
* (agentResponse) keeps working. Must stay AFTER AgentResponse: class fields
|
|
522
|
+
* initialise in order, and the other way round this captures undefined.
|
|
523
|
+
*/
|
|
524
|
+
agentResponse = this.AgentResponse;
|
|
525
|
+
/**
|
|
526
|
+
* Cancelable — fired once per agent turn, on every route, after routing has picked the agent
|
|
527
|
+
* and BEFORE any reply row exists. Listeners may set `event.Cancel = true` to stop the turn
|
|
528
|
+
* (nothing more is written, and {@link AfterAgentTurn} does not fire) or set
|
|
529
|
+
* `event.RedirectAgentId` to send it to another allowed agent. A message that starts no turn
|
|
530
|
+
* fires nothing. Follows MJ's established Before/After cancelable event pattern.
|
|
531
|
+
*/
|
|
532
|
+
BeforeAgentTurn = new EventEmitter();
|
|
533
|
+
/**
|
|
534
|
+
* @deprecated Use {@link BeforeAgentTurn}.
|
|
535
|
+
*
|
|
536
|
+
* The same emitter under the old binding name, so a template still binding
|
|
537
|
+
* (beforeAgentTurn) keeps working. Must stay AFTER BeforeAgentTurn: class fields
|
|
538
|
+
* initialise in order, and the other way round this captures undefined.
|
|
539
|
+
*/
|
|
540
|
+
beforeAgentTurn = this.BeforeAgentTurn;
|
|
541
|
+
/**
|
|
542
|
+
* Fired AFTER a successful agent turn, on every route. Carries the agent run id and the
|
|
543
|
+
* full agent result. Not fired when {@link BeforeAgentTurn} was canceled, when the turn
|
|
544
|
+
* failed, or when a host {@link AgentTurnHandler} reported no result.
|
|
545
|
+
*/
|
|
546
|
+
AfterAgentTurn = new EventEmitter();
|
|
547
|
+
/**
|
|
548
|
+
* @deprecated Use {@link AfterAgentTurn}.
|
|
549
|
+
*
|
|
550
|
+
* The same emitter under the old binding name, so a template still binding
|
|
551
|
+
* (afterAgentTurn) keeps working. Must stay AFTER AfterAgentTurn: class fields
|
|
552
|
+
* initialise in order, and the other way round this captures undefined.
|
|
553
|
+
*/
|
|
554
|
+
afterAgentTurn = this.AfterAgentTurn;
|
|
246
555
|
// conversationId is carried on every agent-lifecycle event so the parent chat-area can drop
|
|
247
556
|
// events emitted by a BACKGROUND conversation's (hidden, still-streaming) input after the user
|
|
248
557
|
// has swapped conversations — preventing cross-conversation state/cache bleed. Sourced from the
|
|
249
558
|
// ConversationDetail entity's ConversationID (the captured, immutable value), never this.conversationId.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
559
|
+
AgentRunDetected = new EventEmitter();
|
|
560
|
+
/**
|
|
561
|
+
* @deprecated Use {@link AgentRunDetected}.
|
|
562
|
+
*
|
|
563
|
+
* The same emitter under the old binding name, so a template still binding
|
|
564
|
+
* (agentRunDetected) keeps working. Must stay AFTER AgentRunDetected: class fields
|
|
565
|
+
* initialise in order, and the other way round this captures undefined.
|
|
566
|
+
*/
|
|
567
|
+
agentRunDetected = this.AgentRunDetected;
|
|
568
|
+
AgentRunUpdate = new EventEmitter();
|
|
569
|
+
/**
|
|
570
|
+
* @deprecated Use {@link AgentRunUpdate}.
|
|
571
|
+
*
|
|
572
|
+
* The same emitter under the old binding name, so a template still binding
|
|
573
|
+
* (agentRunUpdate) keeps working. Must stay AFTER AgentRunUpdate: class fields
|
|
574
|
+
* initialise in order, and the other way round this captures undefined.
|
|
575
|
+
*/
|
|
576
|
+
agentRunUpdate = this.AgentRunUpdate; // Emits when agent run data updates during progress
|
|
577
|
+
MessageComplete = new EventEmitter();
|
|
578
|
+
/**
|
|
579
|
+
* @deprecated Use {@link MessageComplete}.
|
|
580
|
+
*
|
|
581
|
+
* The same emitter under the old binding name, so a template still binding
|
|
582
|
+
* (messageComplete) keeps working. Must stay AFTER MessageComplete: class fields
|
|
583
|
+
* initialise in order, and the other way round this captures undefined.
|
|
584
|
+
*/
|
|
585
|
+
messageComplete = this.MessageComplete; // Emits when message completes (success or error)
|
|
586
|
+
ArtifactCreated = new EventEmitter();
|
|
587
|
+
/**
|
|
588
|
+
* @deprecated Use {@link ArtifactCreated}.
|
|
589
|
+
*
|
|
590
|
+
* The same emitter under the old binding name, so a template still binding
|
|
591
|
+
* (artifactCreated) keeps working. Must stay AFTER ArtifactCreated: class fields
|
|
592
|
+
* initialise in order, and the other way round this captures undefined.
|
|
593
|
+
*/
|
|
594
|
+
artifactCreated = this.ArtifactCreated;
|
|
595
|
+
ConversationRenamed = new EventEmitter();
|
|
596
|
+
/**
|
|
597
|
+
* @deprecated Use {@link ConversationRenamed}.
|
|
598
|
+
*
|
|
599
|
+
* The same emitter under the old binding name, so a template still binding
|
|
600
|
+
* (conversationRenamed) keeps working. Must stay AFTER ConversationRenamed: class fields
|
|
601
|
+
* initialise in order, and the other way round this captures undefined.
|
|
602
|
+
*/
|
|
603
|
+
conversationRenamed = this.ConversationRenamed;
|
|
604
|
+
IntentCheckStarted = new EventEmitter();
|
|
605
|
+
/**
|
|
606
|
+
* @deprecated Use {@link IntentCheckStarted}.
|
|
607
|
+
*
|
|
608
|
+
* The same emitter under the old binding name, so a template still binding
|
|
609
|
+
* (intentCheckStarted) keeps working. Must stay AFTER IntentCheckStarted: class fields
|
|
610
|
+
* initialise in order, and the other way round this captures undefined.
|
|
611
|
+
*/
|
|
612
|
+
intentCheckStarted = this.IntentCheckStarted; // Emits when intent checking starts
|
|
613
|
+
IntentCheckCompleted = new EventEmitter();
|
|
614
|
+
/**
|
|
615
|
+
* @deprecated Use {@link IntentCheckCompleted}.
|
|
616
|
+
*
|
|
617
|
+
* The same emitter under the old binding name, so a template still binding
|
|
618
|
+
* (intentCheckCompleted) keeps working. Must stay AFTER IntentCheckCompleted: class fields
|
|
619
|
+
* initialise in order, and the other way round this captures undefined.
|
|
620
|
+
*/
|
|
621
|
+
intentCheckCompleted = this.IntentCheckCompleted; // Emits when intent checking completes (carries conversationId so the parent can drop a background conversation's completion after a swap — symmetric with intentCheckStarted)
|
|
622
|
+
InitialMessageAutoSendStarted = new EventEmitter();
|
|
623
|
+
/**
|
|
624
|
+
* @deprecated Use {@link InitialMessageAutoSendStarted}.
|
|
625
|
+
*
|
|
626
|
+
* The same emitter under the old binding name, so a template still binding
|
|
627
|
+
* (initialMessageAutoSendStarted) keeps working. Must stay AFTER InitialMessageAutoSendStarted: class fields
|
|
628
|
+
* initialise in order, and the other way round this captures undefined.
|
|
629
|
+
*/
|
|
630
|
+
initialMessageAutoSendStarted = this.InitialMessageAutoSendStarted; // Emitted when this input latches the pending first message for auto-send
|
|
631
|
+
InitialMessageAutoSendFailed = new EventEmitter();
|
|
632
|
+
/**
|
|
633
|
+
* @deprecated Use {@link InitialMessageAutoSendFailed}.
|
|
634
|
+
*
|
|
635
|
+
* The same emitter under the old binding name, so a template still binding
|
|
636
|
+
* (initialMessageAutoSendFailed) keeps working. Must stay AFTER InitialMessageAutoSendFailed: class fields
|
|
637
|
+
* initialise in order, and the other way round this captures undefined.
|
|
638
|
+
*/
|
|
639
|
+
initialMessageAutoSendFailed = this.InitialMessageAutoSendFailed; // Emitted when a latched pending first message fails before messageSent
|
|
640
|
+
EmptyStateSubmit = new EventEmitter();
|
|
641
|
+
/**
|
|
642
|
+
* @deprecated Use {@link EmptyStateSubmit}.
|
|
643
|
+
*
|
|
644
|
+
* The same emitter under the old binding name, so a template still binding
|
|
645
|
+
* (emptyStateSubmit) keeps working. Must stay AFTER EmptyStateSubmit: class fields
|
|
646
|
+
* initialise in order, and the other way round this captures undefined.
|
|
647
|
+
*/
|
|
648
|
+
emptyStateSubmit = this.EmptyStateSubmit; // Emitted when in emptyStateMode
|
|
649
|
+
UploadStateChanged = new EventEmitter();
|
|
650
|
+
/**
|
|
651
|
+
* @deprecated Use {@link UploadStateChanged}.
|
|
652
|
+
*
|
|
653
|
+
* The same emitter under the old binding name, so a template still binding
|
|
654
|
+
* (uploadStateChanged) keeps working. Must stay AFTER UploadStateChanged: class fields
|
|
655
|
+
* initialise in order, and the other way round this captures undefined.
|
|
656
|
+
*/
|
|
657
|
+
uploadStateChanged = this.UploadStateChanged; // Emits when attachment upload state changes
|
|
658
|
+
InputBox;
|
|
659
|
+
/** @deprecated Use {@link InputBox}. */
|
|
660
|
+
get inputBox() {
|
|
661
|
+
return this.InputBox;
|
|
662
|
+
}
|
|
663
|
+
/** @deprecated Use {@link InputBox}. */
|
|
664
|
+
set inputBox(value) {
|
|
665
|
+
this.InputBox = value;
|
|
666
|
+
}
|
|
262
667
|
_messageText = '';
|
|
263
668
|
/**
|
|
264
669
|
* The composer's text. An accessor pair rather than a plain field because every write reaches the
|
|
@@ -274,13 +679,21 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
274
679
|
* Read is a plain field read; there is no two-way `ngModel` on this property (the template binds
|
|
275
680
|
* `[value]="messageText"` one-way), so the pair is transparent to callers.
|
|
276
681
|
*/
|
|
277
|
-
get
|
|
682
|
+
get MessageText() {
|
|
278
683
|
return this._messageText;
|
|
279
684
|
}
|
|
280
|
-
set
|
|
685
|
+
set MessageText(value) {
|
|
281
686
|
this._messageText = value;
|
|
282
687
|
this.mentionedAgentId = undefined;
|
|
283
688
|
}
|
|
689
|
+
/** @deprecated Use {@link MessageText}. */
|
|
690
|
+
get messageText() {
|
|
691
|
+
return this.MessageText;
|
|
692
|
+
}
|
|
693
|
+
/** @deprecated Use {@link MessageText}. */
|
|
694
|
+
set messageText(value) {
|
|
695
|
+
this.MessageText = value;
|
|
696
|
+
}
|
|
284
697
|
/**
|
|
285
698
|
* Prefills the composer with draft text WITHOUT sending (unlike pendingMessage,
|
|
286
699
|
* which auto-sends) and focuses the input — e.g. the omnibar's '@agent' flow
|
|
@@ -292,24 +705,40 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
292
705
|
* view isn't up yet, ngAfterViewInit applies it. Emits initialDraftApplied so the
|
|
293
706
|
* host can clear its pending state.
|
|
294
707
|
*/
|
|
295
|
-
set
|
|
708
|
+
set InitialDraft(value) {
|
|
296
709
|
if (value && value !== this.appliedInitialDraft) {
|
|
297
710
|
this.appliedInitialDraft = value;
|
|
298
|
-
if (this.
|
|
711
|
+
if (this.InputBox) {
|
|
299
712
|
this.SetDraft(value, true);
|
|
300
|
-
this.
|
|
713
|
+
this.InitialDraftApplied.emit();
|
|
301
714
|
}
|
|
302
715
|
else {
|
|
303
716
|
this.pendingInitialDraft = value;
|
|
304
717
|
}
|
|
305
718
|
}
|
|
306
719
|
}
|
|
307
|
-
get
|
|
720
|
+
get InitialDraft() {
|
|
308
721
|
return this.appliedInitialDraft;
|
|
309
722
|
}
|
|
723
|
+
/** @deprecated Use {@link InitialDraft}. */
|
|
724
|
+
get initialDraft() {
|
|
725
|
+
return this.InitialDraft;
|
|
726
|
+
}
|
|
727
|
+
/** @deprecated Use {@link InitialDraft}. */
|
|
728
|
+
set initialDraft(value) {
|
|
729
|
+
this.InitialDraft = value;
|
|
730
|
+
}
|
|
310
731
|
appliedInitialDraft = null;
|
|
311
732
|
pendingInitialDraft = null;
|
|
312
|
-
|
|
733
|
+
InitialDraftApplied = new EventEmitter();
|
|
734
|
+
/**
|
|
735
|
+
* @deprecated Use {@link InitialDraftApplied}.
|
|
736
|
+
*
|
|
737
|
+
* The same emitter under the old binding name, so a template still binding
|
|
738
|
+
* (initialDraftApplied) keeps working. Must stay AFTER InitialDraftApplied: class fields
|
|
739
|
+
* initialise in order, and the other way round this captures undefined.
|
|
740
|
+
*/
|
|
741
|
+
initialDraftApplied = this.InitialDraftApplied;
|
|
313
742
|
/**
|
|
314
743
|
* Live draft-state signal: fires on every composer value change with the
|
|
315
744
|
* SERIALIZED content (mention pills encoded via getPlainTextWithJsonMentions,
|
|
@@ -320,12 +749,12 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
320
749
|
ComposerBlurred = new EventEmitter();
|
|
321
750
|
/** Handles the composer's value stream: keeps messageText in sync + emits draft state. */
|
|
322
751
|
OnComposerValueChanged(value) {
|
|
323
|
-
this.
|
|
752
|
+
this.MessageText = value;
|
|
324
753
|
this.DraftStateChanged.emit(this.GetSerializedDraft());
|
|
325
754
|
}
|
|
326
755
|
/** Current composer content in the lossless serialized form ('' when empty). */
|
|
327
756
|
GetSerializedDraft() {
|
|
328
|
-
const serialized = this.
|
|
757
|
+
const serialized = this.InputBox?.getPlainTextWithJsonMentions() ?? this.MessageText ?? '';
|
|
329
758
|
return serialized.trim().length === 0 ? '' : serialized;
|
|
330
759
|
}
|
|
331
760
|
/**
|
|
@@ -338,27 +767,27 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
338
767
|
* @returns false while the composer view isn't mounted yet — callers may retry.
|
|
339
768
|
*/
|
|
340
769
|
async InsertAgentMention(agentName, focus = true, clearExisting = true) {
|
|
341
|
-
if (!this.
|
|
770
|
+
if (!this.InputBox) {
|
|
342
771
|
console.log(`[Omnibar→Chat] InsertAgentMention('${agentName}'): input box not mounted yet — caller will retry`);
|
|
343
772
|
return false;
|
|
344
773
|
}
|
|
345
774
|
if (clearExisting) {
|
|
346
775
|
// Pre-addressing REPLACES any un-sent draft (tagging agent B after agent A
|
|
347
776
|
// must not stack pills).
|
|
348
|
-
this.
|
|
349
|
-
this.
|
|
777
|
+
this.InputBox.mentionEditor?.clear();
|
|
778
|
+
this.MessageText = '';
|
|
350
779
|
}
|
|
351
780
|
try {
|
|
352
|
-
if (!this.mentionAutocomplete.IsInitialized && this.
|
|
781
|
+
if (!this.mentionAutocomplete.IsInitialized && this.CurrentUser) {
|
|
353
782
|
console.log(`[Omnibar→Chat] InsertAgentMention('${agentName}'): initializing mention autocomplete…`);
|
|
354
|
-
await this.mentionAutocomplete.initialize(this.
|
|
783
|
+
await this.mentionAutocomplete.initialize(this.CurrentUser);
|
|
355
784
|
}
|
|
356
785
|
const wanted = agentName.trim().toLowerCase();
|
|
357
786
|
const suggestion = this.mentionAutocomplete
|
|
358
787
|
.getSuggestions(agentName, false, '@')
|
|
359
788
|
.find(s => s.type === 'agent' && s.name.trim().toLowerCase() === wanted);
|
|
360
789
|
if (suggestion) {
|
|
361
|
-
const inserted = this.
|
|
790
|
+
const inserted = this.InputBox.InsertMention(suggestion, focus);
|
|
362
791
|
console.log(`[Omnibar→Chat] InsertAgentMention('${agentName}'): resolved to pill (id=${suggestion.id}) — insert ${inserted ? 'OK' : 'FAILED (editor view not ready)'}`);
|
|
363
792
|
if (inserted) {
|
|
364
793
|
if (focus) {
|
|
@@ -385,7 +814,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
385
814
|
scheduleFocusReassert(context) {
|
|
386
815
|
for (const delay of [300, 900, 1800]) {
|
|
387
816
|
setTimeout(() => {
|
|
388
|
-
const editor = this.
|
|
817
|
+
const editor = this.InputBox?.mentionEditor;
|
|
389
818
|
if (editor && !editor.HasFocus) {
|
|
390
819
|
const ok = editor.FocusCaretAtEnd();
|
|
391
820
|
console.log(`[Omnibar→Chat] focus re-assert (+${delay}ms) for '${context}': ${ok ? 'refocused' : 'editor gone'}`);
|
|
@@ -394,18 +823,66 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
394
823
|
}
|
|
395
824
|
}
|
|
396
825
|
SetDraft(text, focus = true) {
|
|
397
|
-
this.
|
|
826
|
+
this.MessageText = text;
|
|
398
827
|
if (focus) {
|
|
399
828
|
// The composer mounts/binds on the next tick after messageText flows down.
|
|
400
|
-
setTimeout(() => this.
|
|
401
|
-
}
|
|
829
|
+
setTimeout(() => this.InputBox?.focus(), 50);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
IsSending = false;
|
|
833
|
+
/** @deprecated Use {@link IsSending}. */
|
|
834
|
+
get isSending() {
|
|
835
|
+
return this.IsSending;
|
|
836
|
+
}
|
|
837
|
+
/** @deprecated Use {@link IsSending}. */
|
|
838
|
+
set isSending(value) {
|
|
839
|
+
this.IsSending = value;
|
|
840
|
+
}
|
|
841
|
+
IsProcessing = false;
|
|
842
|
+
/** @deprecated Use {@link IsProcessing}. */
|
|
843
|
+
get isProcessing() {
|
|
844
|
+
return this.IsProcessing;
|
|
845
|
+
}
|
|
846
|
+
/** @deprecated Use {@link IsProcessing}. */
|
|
847
|
+
set isProcessing(value) {
|
|
848
|
+
this.IsProcessing = value;
|
|
849
|
+
} // True when waiting for agent/naming response
|
|
850
|
+
ProcessingMessage = 'AI is responding...';
|
|
851
|
+
/** @deprecated Use {@link ProcessingMessage}. */
|
|
852
|
+
get processingMessage() {
|
|
853
|
+
return this.ProcessingMessage;
|
|
854
|
+
}
|
|
855
|
+
/** @deprecated Use {@link ProcessingMessage}. */
|
|
856
|
+
set processingMessage(value) {
|
|
857
|
+
this.ProcessingMessage = value;
|
|
858
|
+
} // Message shown during processing
|
|
859
|
+
IsUploadingAttachments = false;
|
|
860
|
+
/** @deprecated Use {@link IsUploadingAttachments}. */
|
|
861
|
+
get isUploadingAttachments() {
|
|
862
|
+
return this.IsUploadingAttachments;
|
|
863
|
+
}
|
|
864
|
+
/** @deprecated Use {@link IsUploadingAttachments}. */
|
|
865
|
+
set isUploadingAttachments(value) {
|
|
866
|
+
this.IsUploadingAttachments = value;
|
|
867
|
+
} // True when uploading attachments to server
|
|
868
|
+
UploadingMessage = 'Uploading attachments...';
|
|
869
|
+
/** @deprecated Use {@link UploadingMessage}. */
|
|
870
|
+
get uploadingMessage() {
|
|
871
|
+
return this.UploadingMessage;
|
|
872
|
+
}
|
|
873
|
+
/** @deprecated Use {@link UploadingMessage}. */
|
|
874
|
+
set uploadingMessage(value) {
|
|
875
|
+
this.UploadingMessage = value;
|
|
876
|
+
} // Message shown during upload
|
|
877
|
+
ConverationManagerAgent = null;
|
|
878
|
+
/** @deprecated Use {@link ConverationManagerAgent}. */
|
|
879
|
+
get converationManagerAgent() {
|
|
880
|
+
return this.ConverationManagerAgent;
|
|
881
|
+
}
|
|
882
|
+
/** @deprecated Use {@link ConverationManagerAgent}. */
|
|
883
|
+
set converationManagerAgent(value) {
|
|
884
|
+
this.ConverationManagerAgent = value;
|
|
402
885
|
}
|
|
403
|
-
isSending = false;
|
|
404
|
-
isProcessing = false; // True when waiting for agent/naming response
|
|
405
|
-
processingMessage = 'AI is responding...'; // Message shown during processing
|
|
406
|
-
isUploadingAttachments = false; // True when uploading attachments to server
|
|
407
|
-
uploadingMessage = 'Uploading attachments...'; // Message shown during upload
|
|
408
|
-
converationManagerAgent = null;
|
|
409
886
|
// Track completion timestamps to prevent race conditions with late progress updates
|
|
410
887
|
completionTimestamps = new Map();
|
|
411
888
|
// Track registered streaming callbacks for cleanup
|
|
@@ -437,7 +914,15 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
437
914
|
}
|
|
438
915
|
// ── Voice session (Realtime Co-Agent) ───────────────────────────────
|
|
439
916
|
/** True while a live voice session is active — drives the overlay + mic state. */
|
|
440
|
-
|
|
917
|
+
VoiceActive = false;
|
|
918
|
+
/** @deprecated Use {@link VoiceActive}. */
|
|
919
|
+
get voiceActive() {
|
|
920
|
+
return this.VoiceActive;
|
|
921
|
+
}
|
|
922
|
+
/** @deprecated Use {@link VoiceActive}. */
|
|
923
|
+
set voiceActive(value) {
|
|
924
|
+
this.VoiceActive = value;
|
|
925
|
+
}
|
|
441
926
|
realtimeActiveSub;
|
|
442
927
|
async ngOnInit() {
|
|
443
928
|
// Bind provider-aware services to this component's provider.
|
|
@@ -449,16 +934,16 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
449
934
|
this.realtimeSession.Provider = p;
|
|
450
935
|
// Reflect the live voice-session Active flag into a local field for the template.
|
|
451
936
|
this.realtimeActiveSub = this.realtimeSession.Active$.subscribe(active => {
|
|
452
|
-
this.
|
|
937
|
+
this.VoiceActive = active;
|
|
453
938
|
});
|
|
454
|
-
this.
|
|
939
|
+
this.ConverationManagerAgent = await this.agentService.getConversationManagerAgent();
|
|
455
940
|
// Warm UserInfoEngine so the PlanModeEnabled getter has the cached settings available
|
|
456
941
|
// (no-op when already loaded; failure just leaves the toggle at its default OFF).
|
|
457
942
|
PlanModePreference.Warm();
|
|
458
943
|
// Initialize mention autocomplete (needed for parsing mentions in messages)
|
|
459
|
-
await this.mentionAutocomplete.initialize(this.
|
|
944
|
+
await this.mentionAutocomplete.initialize(this.CurrentUser);
|
|
460
945
|
// Reconnect to any in-progress messages for streaming updates (via global streaming service)
|
|
461
|
-
this.
|
|
946
|
+
this.ReconnectInProgressMessages();
|
|
462
947
|
}
|
|
463
948
|
ngOnChanges(changes) {
|
|
464
949
|
// When conversation changes, focus the input
|
|
@@ -474,7 +959,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
474
959
|
// next tick — the composer's own view finishes mounting first
|
|
475
960
|
setTimeout(() => {
|
|
476
961
|
this.SetDraft(draft, true);
|
|
477
|
-
this.
|
|
962
|
+
this.InitialDraftApplied.emit();
|
|
478
963
|
}, 50);
|
|
479
964
|
}
|
|
480
965
|
// Focus input on initial load
|
|
@@ -494,23 +979,23 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
494
979
|
const message = this._initialMessage;
|
|
495
980
|
const attachments = this._initialAttachments;
|
|
496
981
|
const hasContent = !!message || !!(attachments && attachments.length > 0);
|
|
497
|
-
if (!hasContent || !this.
|
|
982
|
+
if (!hasContent || !this.ConversationId || UUIDsEqual(this._autoSentForConversationId, this.ConversationId)) {
|
|
498
983
|
return;
|
|
499
984
|
}
|
|
500
|
-
this._autoSentForConversationId = this.
|
|
985
|
+
this._autoSentForConversationId = this.ConversationId;
|
|
501
986
|
// Set pending attachments before sending
|
|
502
987
|
if (attachments && attachments.length > 0) {
|
|
503
988
|
this.pendingAttachments = [...attachments];
|
|
504
989
|
}
|
|
505
990
|
Promise.resolve().then(() => {
|
|
506
|
-
this.
|
|
991
|
+
this.InitialMessageAutoSendStarted.emit({ conversationId: this.ConversationId });
|
|
507
992
|
});
|
|
508
993
|
// Use setTimeout to ensure we're outside of change detection cycle
|
|
509
994
|
setTimeout(async () => {
|
|
510
|
-
const sent = await this.
|
|
995
|
+
const sent = await this.SendMessageWithText(message || '');
|
|
511
996
|
if (!sent) {
|
|
512
997
|
this._autoSentForConversationId = null;
|
|
513
|
-
this.
|
|
998
|
+
this.InitialMessageAutoSendFailed.emit({ conversationId: this.ConversationId });
|
|
514
999
|
}
|
|
515
1000
|
}, 100);
|
|
516
1001
|
}
|
|
@@ -531,14 +1016,17 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
531
1016
|
* 2. per-conversation pinned default
|
|
532
1017
|
* 3. embedder-supplied default
|
|
533
1018
|
* 4. Sage fallback
|
|
534
|
-
*
|
|
1019
|
+
* skipping any agent outside {@link AllowedAgentIDs}. {@link AgentReplyMode} does not apply:
|
|
1020
|
+
* starting a call is itself a choice to talk to an agent. Returns null when Sage failed to
|
|
1021
|
+
* load, or when the host allows none of these agents.
|
|
535
1022
|
*/
|
|
1023
|
+
ResolveCurrentAgentId() {
|
|
1024
|
+
const target = ResolveAgentTurn(this.agentTurnCandidates([]), { ReplyMode: 'Always', AllowedAgentIDs: this.AllowedAgentIDs }, () => true);
|
|
1025
|
+
return target?.AgentId ?? null;
|
|
1026
|
+
}
|
|
1027
|
+
/** @deprecated Use {@link ResolveCurrentAgentId}. */
|
|
536
1028
|
resolveCurrentAgentId() {
|
|
537
|
-
return this.
|
|
538
|
-
?? this.conversationDefaultAgentId
|
|
539
|
-
?? this.defaultAgentId
|
|
540
|
-
?? this.converationManagerAgent?.ID
|
|
541
|
-
?? null;
|
|
1029
|
+
return this.ResolveCurrentAgentId();
|
|
542
1030
|
}
|
|
543
1031
|
/**
|
|
544
1032
|
* The agent the '/' skill picker should narrow to. Mirrors routing's priority: an explicit
|
|
@@ -546,12 +1034,16 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
546
1034
|
* would otherwise go to ({@link resolveCurrentAgentId}). Bound to `mj-ai-composer`'s
|
|
547
1035
|
* `TargetAgentId`; null = unknown, no narrowing.
|
|
548
1036
|
*/
|
|
549
|
-
get
|
|
1037
|
+
get PickerTargetAgentId() {
|
|
550
1038
|
if (this.mentionedAgentId === undefined) {
|
|
551
|
-
const chips = this.
|
|
1039
|
+
const chips = this.InputBox?.getMentionChipsData() || [];
|
|
552
1040
|
this.mentionedAgentId = chips.find(chip => chip.type === 'agent')?.id ?? null;
|
|
553
1041
|
}
|
|
554
|
-
return this.mentionedAgentId ?? this.
|
|
1042
|
+
return this.mentionedAgentId ?? this.ResolveCurrentAgentId();
|
|
1043
|
+
}
|
|
1044
|
+
/** @deprecated Use {@link PickerTargetAgentId}. */
|
|
1045
|
+
get pickerTargetAgentId() {
|
|
1046
|
+
return this.PickerTargetAgentId;
|
|
555
1047
|
}
|
|
556
1048
|
/**
|
|
557
1049
|
* Memo for the first `@agent` chip in the draft, so the template-bound
|
|
@@ -582,8 +1074,12 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
582
1074
|
*/
|
|
583
1075
|
mentionedAgentId = undefined;
|
|
584
1076
|
/** True when the mic button should be enabled (have an agent + not disabled). */
|
|
1077
|
+
get CanStartRealtime() {
|
|
1078
|
+
return !this.Disabled && !this.VoiceActive && !!this.ResolveCurrentAgentId();
|
|
1079
|
+
}
|
|
1080
|
+
/** @deprecated Use {@link CanStartRealtime}. */
|
|
585
1081
|
get canStartRealtime() {
|
|
586
|
-
return
|
|
1082
|
+
return this.CanStartRealtime;
|
|
587
1083
|
}
|
|
588
1084
|
/**
|
|
589
1085
|
* Display name of the agent the voice session fronts. Resolved here (this component
|
|
@@ -591,7 +1087,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
591
1087
|
* session start so the chat-area-hosted overlay can read it from the service.
|
|
592
1088
|
*/
|
|
593
1089
|
resolveRealtimeAgentName() {
|
|
594
|
-
const agentId = this.
|
|
1090
|
+
const agentId = this.ResolveCurrentAgentId();
|
|
595
1091
|
if (agentId) {
|
|
596
1092
|
const match = this.mentionAutocomplete
|
|
597
1093
|
.getAvailableAgents()
|
|
@@ -600,10 +1096,18 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
600
1096
|
return match.Name;
|
|
601
1097
|
}
|
|
602
1098
|
}
|
|
603
|
-
return this.
|
|
1099
|
+
return this.ConverationManagerAgent?.Name ?? 'Sage';
|
|
604
1100
|
}
|
|
605
1101
|
/** True while the "Start a voice call with…" agent picker popover is open. */
|
|
606
|
-
|
|
1102
|
+
ShowRealtimeAgentPicker = false;
|
|
1103
|
+
/** @deprecated Use {@link ShowRealtimeAgentPicker}. */
|
|
1104
|
+
get showRealtimeAgentPicker() {
|
|
1105
|
+
return this.ShowRealtimeAgentPicker;
|
|
1106
|
+
}
|
|
1107
|
+
/** @deprecated Use {@link ShowRealtimeAgentPicker}. */
|
|
1108
|
+
set showRealtimeAgentPicker(value) {
|
|
1109
|
+
this.ShowRealtimeAgentPicker = value;
|
|
1110
|
+
}
|
|
607
1111
|
/**
|
|
608
1112
|
* CDK connected-overlay positions for the voice agent picker. Preferred: open UPWARD,
|
|
609
1113
|
* right edge aligned to the composer's right edge (matching the old absolute placement).
|
|
@@ -611,40 +1115,79 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
611
1115
|
* body-level CDK overlay container (with `cdkConnectedOverlayPush`), it escapes the chat
|
|
612
1116
|
* overlay's `overflow: hidden` border and can never clip at the top of a narrow overlay.
|
|
613
1117
|
*/
|
|
614
|
-
|
|
1118
|
+
PickerOverlayPositions = [
|
|
615
1119
|
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -8 },
|
|
616
1120
|
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 8 },
|
|
617
1121
|
];
|
|
1122
|
+
/** @deprecated Use {@link PickerOverlayPositions}. */
|
|
1123
|
+
get pickerOverlayPositions() {
|
|
1124
|
+
return this.PickerOverlayPositions;
|
|
1125
|
+
}
|
|
618
1126
|
/**
|
|
619
1127
|
* `MJ: User Settings` key persisting the user's co-agent choice for realtime calls
|
|
620
1128
|
* (server-side, cross-device — never localStorage). Stored shape: `{"coAgentId":
|
|
621
1129
|
* string | null}` — `null` is an explicit "Auto" choice that overwrites an older pick.
|
|
622
1130
|
*/
|
|
623
|
-
static
|
|
1131
|
+
static coAgentPrefKey = 'mj.realtimeVoice.coAgent.v1';
|
|
624
1132
|
/**
|
|
625
1133
|
* The persisted co-agent preference, loaded just before the picker opens (and read by
|
|
626
1134
|
* the instant-start path). `null` = no preference / explicit "Auto".
|
|
627
1135
|
*/
|
|
628
|
-
|
|
1136
|
+
VoicePickerDefaultCoAgentId = null;
|
|
1137
|
+
/** @deprecated Use {@link VoicePickerDefaultCoAgentId}. */
|
|
1138
|
+
get voicePickerDefaultCoAgentId() {
|
|
1139
|
+
return this.VoicePickerDefaultCoAgentId;
|
|
1140
|
+
}
|
|
1141
|
+
/** @deprecated Use {@link VoicePickerDefaultCoAgentId}. */
|
|
1142
|
+
set voicePickerDefaultCoAgentId(value) {
|
|
1143
|
+
this.VoicePickerDefaultCoAgentId = value;
|
|
1144
|
+
}
|
|
629
1145
|
/**
|
|
630
1146
|
* Agents the voice picker offers — the same cached set the @mention
|
|
631
|
-
* autocomplete and {@link resolveRealtimeAgentName} use,
|
|
632
|
-
* never offer an agent the
|
|
633
|
-
|
|
1147
|
+
* autocomplete and {@link resolveRealtimeAgentName} use, narrowed to
|
|
1148
|
+
* {@link AllowedAgentIDs}, so the picker can never offer an agent the
|
|
1149
|
+
* conversation couldn't otherwise route to.
|
|
1150
|
+
*/
|
|
1151
|
+
get VoicePickerAgents() {
|
|
1152
|
+
const agents = this.mentionAutocomplete.getAvailableAgents();
|
|
1153
|
+
const allowed = this.AllowedAgentIDs;
|
|
1154
|
+
if (allowed == null) {
|
|
1155
|
+
return agents;
|
|
1156
|
+
}
|
|
1157
|
+
// Memoized on both inputs: the picker binds this getter, and a fresh array on every
|
|
1158
|
+
// change-detection pass would look like a new input each time.
|
|
1159
|
+
const memo = this.voicePickerAgentsMemo;
|
|
1160
|
+
if (memo && memo.Source === agents && memo.Allowed === allowed) {
|
|
1161
|
+
return memo.Result;
|
|
1162
|
+
}
|
|
1163
|
+
const result = agents.filter(agent => IsAgentAllowed(agent.ID, allowed));
|
|
1164
|
+
this.voicePickerAgentsMemo = { Source: agents, Allowed: allowed, Result: result };
|
|
1165
|
+
return result;
|
|
1166
|
+
}
|
|
1167
|
+
voicePickerAgentsMemo = null;
|
|
1168
|
+
/** @deprecated Use {@link VoicePickerAgents}. */
|
|
634
1169
|
get voicePickerAgents() {
|
|
635
|
-
return this.
|
|
1170
|
+
return this.VoicePickerAgents;
|
|
636
1171
|
}
|
|
637
1172
|
/**
|
|
638
1173
|
* The ACTIVE Realtime-type co-agent candidates — the same run-permission-filtered
|
|
639
1174
|
* cached set as {@link voicePickerAgents}, narrowed to the Realtime agent type. The
|
|
640
1175
|
* picker shows its co-agent selector only when more than one exists.
|
|
641
1176
|
*/
|
|
642
|
-
get
|
|
1177
|
+
get VoicePickerCoAgents() {
|
|
643
1178
|
return FilterRealtimeCoAgents(this.mentionAutocomplete.getAvailableAgents());
|
|
644
1179
|
}
|
|
1180
|
+
/** @deprecated Use {@link VoicePickerCoAgents}. */
|
|
1181
|
+
get voicePickerCoAgents() {
|
|
1182
|
+
return this.VoicePickerCoAgents;
|
|
1183
|
+
}
|
|
645
1184
|
/** The agent the default resolution would call — preselected in the picker. */
|
|
1185
|
+
get VoicePickerDefaultAgentId() {
|
|
1186
|
+
return this.ResolveCurrentAgentId();
|
|
1187
|
+
}
|
|
1188
|
+
/** @deprecated Use {@link VoicePickerDefaultAgentId}. */
|
|
646
1189
|
get voicePickerDefaultAgentId() {
|
|
647
|
-
return this.
|
|
1190
|
+
return this.VoicePickerDefaultAgentId;
|
|
648
1191
|
}
|
|
649
1192
|
/**
|
|
650
1193
|
* Start a real-time voice session fronting the conversation's current agent.
|
|
@@ -660,18 +1203,18 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
660
1203
|
* the user never chose — so show a compact agent picker instead and start
|
|
661
1204
|
* with whichever agent they pick.
|
|
662
1205
|
*/
|
|
663
|
-
async
|
|
664
|
-
if (!this.
|
|
1206
|
+
async OnStartRealtime() {
|
|
1207
|
+
if (!this.CanStartRealtime) {
|
|
665
1208
|
return;
|
|
666
1209
|
}
|
|
667
1210
|
// New/empty conversation (no prior agent turn): let the user choose who
|
|
668
1211
|
// to call. Falls through to the immediate path if the agent cache is
|
|
669
1212
|
// empty (nothing to pick from — the resolved default is the only option).
|
|
670
|
-
if (!this.findLastNonSageAgentId() && this.
|
|
1213
|
+
if (!this.findLastNonSageAgentId() && this.VoicePickerAgents.length > 0) {
|
|
671
1214
|
await this.openRealtimeAgentPicker();
|
|
672
1215
|
return;
|
|
673
1216
|
}
|
|
674
|
-
const targetAgentId = this.
|
|
1217
|
+
const targetAgentId = this.ResolveCurrentAgentId();
|
|
675
1218
|
if (!targetAgentId) {
|
|
676
1219
|
this.toastService.error('No agent available for a voice session.');
|
|
677
1220
|
return;
|
|
@@ -679,6 +1222,10 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
679
1222
|
const coAgentId = await this.resolveInstantCoAgentId(targetAgentId);
|
|
680
1223
|
await this.startRealtimeWithAgent(targetAgentId, this.resolveRealtimeAgentName(), null, coAgentId);
|
|
681
1224
|
}
|
|
1225
|
+
/** @deprecated Use {@link OnStartRealtime}. */
|
|
1226
|
+
async onStartRealtime() {
|
|
1227
|
+
return this.OnStartRealtime();
|
|
1228
|
+
}
|
|
682
1229
|
/**
|
|
683
1230
|
* Caret-next-to-the-phone click: open the agent/co-agent/model picker ON DEMAND, even
|
|
684
1231
|
* when the conversation already has agent history (where the plain phone click
|
|
@@ -687,27 +1234,35 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
687
1234
|
* choice one click away. Falls through to the instant path when there is nothing to
|
|
688
1235
|
* pick from.
|
|
689
1236
|
*/
|
|
690
|
-
async
|
|
691
|
-
if (!this.
|
|
1237
|
+
async OnRealtimeOptions() {
|
|
1238
|
+
if (!this.CanStartRealtime) {
|
|
692
1239
|
return;
|
|
693
1240
|
}
|
|
694
|
-
if (this.
|
|
1241
|
+
if (this.VoicePickerAgents.length > 0) {
|
|
695
1242
|
await this.openRealtimeAgentPicker();
|
|
696
1243
|
return;
|
|
697
1244
|
}
|
|
698
|
-
void this.
|
|
1245
|
+
void this.OnStartRealtime();
|
|
1246
|
+
}
|
|
1247
|
+
/** @deprecated Use {@link OnRealtimeOptions}. */
|
|
1248
|
+
async onRealtimeOptions() {
|
|
1249
|
+
return this.OnRealtimeOptions();
|
|
699
1250
|
}
|
|
700
1251
|
/** Loads the persisted co-agent preference, then shows the picker (pref preselected). */
|
|
701
1252
|
async openRealtimeAgentPicker() {
|
|
702
|
-
this.
|
|
703
|
-
this.
|
|
1253
|
+
this.VoicePickerDefaultCoAgentId = await this.loadPersistedCoAgentId();
|
|
1254
|
+
this.ShowRealtimeAgentPicker = true;
|
|
704
1255
|
}
|
|
705
1256
|
/** User confirmed an agent (+ optional co-agent / voice model) in the voice picker — start the call. */
|
|
706
|
-
async
|
|
707
|
-
this.
|
|
1257
|
+
async OnRealtimeAgentPicked(pick) {
|
|
1258
|
+
this.ShowRealtimeAgentPicker = false;
|
|
708
1259
|
this.persistCoAgentChoice(pick.CoAgentId);
|
|
709
1260
|
await this.startRealtimeWithAgent(pick.Agent.ID, pick.Agent.Name || this.resolveRealtimeAgentName(), pick.PreferredModelId, pick.CoAgentId, BuildRealtimeConfigOverridesJson(pick.PreferredModelId, pick.PreferredVoice), pick.RecordingConsent);
|
|
710
1261
|
}
|
|
1262
|
+
/** @deprecated Use {@link OnRealtimeAgentPicked}. */
|
|
1263
|
+
async onRealtimeAgentPicked(pick) {
|
|
1264
|
+
return this.OnRealtimeAgentPicked(pick);
|
|
1265
|
+
}
|
|
711
1266
|
/**
|
|
712
1267
|
* Reads the persisted co-agent preference from `MJ: User Settings` (via
|
|
713
1268
|
* `UserInfoEngine`'s cached settings). Defensive: any failure or malformed payload
|
|
@@ -716,7 +1271,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
716
1271
|
async loadPersistedCoAgentId() {
|
|
717
1272
|
try {
|
|
718
1273
|
await UserInfoEngine.Instance.Config();
|
|
719
|
-
const raw = UserInfoEngine.Instance.GetSetting(MessageInputComponent.
|
|
1274
|
+
const raw = UserInfoEngine.Instance.GetSetting(MessageInputComponent.coAgentPrefKey);
|
|
720
1275
|
if (!raw) {
|
|
721
1276
|
return null;
|
|
722
1277
|
}
|
|
@@ -730,7 +1285,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
730
1285
|
/** Persists the user's co-agent choice (including explicit "Auto" = null) cross-device. */
|
|
731
1286
|
persistCoAgentChoice(coAgentId) {
|
|
732
1287
|
try {
|
|
733
|
-
UserInfoEngine.Instance.SetSettingDebounced(MessageInputComponent.
|
|
1288
|
+
UserInfoEngine.Instance.SetSettingDebounced(MessageInputComponent.coAgentPrefKey, JSON.stringify({ coAgentId: coAgentId ?? null }));
|
|
734
1289
|
}
|
|
735
1290
|
catch (error) {
|
|
736
1291
|
console.warn('[MessageInput] Failed to persist co-agent preference:', error);
|
|
@@ -749,7 +1304,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
749
1304
|
if (!preferred) {
|
|
750
1305
|
return null;
|
|
751
1306
|
}
|
|
752
|
-
const isValidCandidate = this.
|
|
1307
|
+
const isValidCandidate = this.VoicePickerCoAgents.some(a => UUIDsEqual(a.ID, preferred));
|
|
753
1308
|
if (!isValidCandidate) {
|
|
754
1309
|
return null;
|
|
755
1310
|
}
|
|
@@ -757,8 +1312,12 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
757
1312
|
return PairingsAllowTarget(pairings, targetAgentId) ? preferred : null;
|
|
758
1313
|
}
|
|
759
1314
|
/** User dismissed the voice picker without starting a call. */
|
|
1315
|
+
OnRealtimeAgentPickerCancelled() {
|
|
1316
|
+
this.ShowRealtimeAgentPicker = false;
|
|
1317
|
+
}
|
|
1318
|
+
/** @deprecated Use {@link OnRealtimeAgentPickerCancelled}. */
|
|
760
1319
|
onRealtimeAgentPickerCancelled() {
|
|
761
|
-
this.
|
|
1320
|
+
return this.OnRealtimeAgentPickerCancelled();
|
|
762
1321
|
}
|
|
763
1322
|
/**
|
|
764
1323
|
* Shared session-start path for both the immediate (existing conversation)
|
|
@@ -777,11 +1336,11 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
777
1336
|
*/
|
|
778
1337
|
async startRealtimeWithAgent(agentId, agentName, preferredModelId, coAgentId, configOverridesJson, recordingConsent) {
|
|
779
1338
|
try {
|
|
780
|
-
await this.realtimeSession.StartRealtimeSession(agentId, this.
|
|
1339
|
+
await this.realtimeSession.StartRealtimeSession(agentId, this.ConversationId, null, agentName, preferredModelId ?? null, null, coAgentId ?? null, configOverridesJson ?? null, recordingConsent ?? null, null,
|
|
781
1340
|
// App awareness: the app the session runs in + the live app-context snapshot (where the
|
|
782
1341
|
// user is, what they see, capability manifest) — drives the server-side app cascade + the
|
|
783
1342
|
// mint-time prompt injection, and seeds the ClientContextChannel's streaming.
|
|
784
|
-
this.
|
|
1343
|
+
this.ApplicationId, this.AppContext);
|
|
785
1344
|
}
|
|
786
1345
|
catch (error) {
|
|
787
1346
|
console.error('Failed to start voice session:', error);
|
|
@@ -794,8 +1353,8 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
794
1353
|
focusInput() {
|
|
795
1354
|
// Use setTimeout to ensure DOM is ready
|
|
796
1355
|
setTimeout(() => {
|
|
797
|
-
if (this.
|
|
798
|
-
this.
|
|
1356
|
+
if (this.InputBox) {
|
|
1357
|
+
this.InputBox.focus();
|
|
799
1358
|
}
|
|
800
1359
|
}, 100);
|
|
801
1360
|
}
|
|
@@ -807,14 +1366,14 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
807
1366
|
* 3. User returns to a conversation with in-progress messages
|
|
808
1367
|
* 4. Parent component explicitly triggers reconnection
|
|
809
1368
|
*/
|
|
810
|
-
|
|
811
|
-
if (!this.
|
|
1369
|
+
ReconnectInProgressMessages() {
|
|
1370
|
+
if (!this.InProgressMessageIds || this.InProgressMessageIds.length === 0) {
|
|
812
1371
|
return;
|
|
813
1372
|
}
|
|
814
1373
|
// Unregister any previously registered callbacks for this component
|
|
815
1374
|
this.unregisterAllCallbacks();
|
|
816
1375
|
// Register new callbacks for each in-progress message
|
|
817
|
-
for (const messageId of this.
|
|
1376
|
+
for (const messageId of this.InProgressMessageIds) {
|
|
818
1377
|
// Create callback bound to this message ID
|
|
819
1378
|
const callback = this.createMessageProgressCallback(messageId);
|
|
820
1379
|
// Store reference for cleanup
|
|
@@ -823,6 +1382,10 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
823
1382
|
this.streamingService.registerMessageCallback(messageId, callback);
|
|
824
1383
|
}
|
|
825
1384
|
}
|
|
1385
|
+
/** @deprecated Use {@link ReconnectInProgressMessages}. */
|
|
1386
|
+
reconnectInProgressMessages() {
|
|
1387
|
+
return this.ReconnectInProgressMessages();
|
|
1388
|
+
}
|
|
826
1389
|
/**
|
|
827
1390
|
* Create a progress callback for a specific message ID.
|
|
828
1391
|
* This callback will be invoked by the streaming service when progress updates arrive.
|
|
@@ -835,7 +1398,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
835
1398
|
return async (progress) => {
|
|
836
1399
|
try {
|
|
837
1400
|
// Get message from cache (single source of truth)
|
|
838
|
-
const message = (resolvedMessage ??= await this.dataCache.getConversationDetail(messageId, this.
|
|
1401
|
+
const message = (resolvedMessage ??= await this.dataCache.getConversationDetail(messageId, this.CurrentUser));
|
|
839
1402
|
if (!message) {
|
|
840
1403
|
console.warn(`[StreamingCallback] Message ${messageId} not found in cache`);
|
|
841
1404
|
return;
|
|
@@ -857,7 +1420,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
857
1420
|
// bubble with the server-saved final message, so no append/merge is needed here.
|
|
858
1421
|
if (progress.streaming) {
|
|
859
1422
|
message.Message = progress.streaming.content;
|
|
860
|
-
this.
|
|
1423
|
+
this.MessageSent.emit(message);
|
|
861
1424
|
// Keep the tasks dropdown on a stable status line rather than the growing reply text.
|
|
862
1425
|
this.activeTasks.updateStatusByConversationDetailId(message.ID, 'Responding…');
|
|
863
1426
|
return;
|
|
@@ -875,7 +1438,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
875
1438
|
// Server now saves progress - client only updates in-memory and emits for UI
|
|
876
1439
|
// (Prevents race condition where client's late save overwrites server's final Status)
|
|
877
1440
|
// CRITICAL: Emit update to trigger UI refresh
|
|
878
|
-
this.
|
|
1441
|
+
this.MessageSent.emit(message);
|
|
879
1442
|
// CRITICAL: Update ActiveTasksService to keep the tasks dropdown in sync
|
|
880
1443
|
this.activeTasks.updateStatusByConversationDetailId(message.ID, progress.message);
|
|
881
1444
|
console.log(`[StreamingCallback] Updated message ${messageId}: ${progress.taskName || 'Agent'}`);
|
|
@@ -899,25 +1462,37 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
899
1462
|
}
|
|
900
1463
|
this.registeredCallbacks.clear();
|
|
901
1464
|
}
|
|
1465
|
+
get CanSend() {
|
|
1466
|
+
return !this.Disabled && !this.IsSending && this.MessageText.trim().length > 0;
|
|
1467
|
+
}
|
|
1468
|
+
/** @deprecated Use {@link CanSend}. */
|
|
902
1469
|
get canSend() {
|
|
903
|
-
return
|
|
1470
|
+
return this.CanSend;
|
|
904
1471
|
}
|
|
905
1472
|
/**
|
|
906
1473
|
* Handle attachments changed from the input box
|
|
907
1474
|
*/
|
|
908
|
-
|
|
1475
|
+
OnAttachmentsChanged(attachments) {
|
|
909
1476
|
this.pendingAttachments = attachments;
|
|
910
1477
|
}
|
|
1478
|
+
/** @deprecated Use {@link OnAttachmentsChanged}. */
|
|
1479
|
+
onAttachmentsChanged(attachments) {
|
|
1480
|
+
return this.OnAttachmentsChanged(attachments);
|
|
1481
|
+
}
|
|
911
1482
|
/**
|
|
912
1483
|
* Handle attachment errors from the input box
|
|
913
1484
|
*/
|
|
914
|
-
|
|
1485
|
+
OnAttachmentError(error) {
|
|
915
1486
|
this.toastService.error(error);
|
|
916
1487
|
}
|
|
1488
|
+
/** @deprecated Use {@link OnAttachmentError}. */
|
|
1489
|
+
onAttachmentError(error) {
|
|
1490
|
+
return this.OnAttachmentError(error);
|
|
1491
|
+
}
|
|
917
1492
|
/**
|
|
918
1493
|
* Handle text submitted from the input box
|
|
919
1494
|
*/
|
|
920
|
-
async
|
|
1495
|
+
async OnTextSubmitted(text) {
|
|
921
1496
|
// Check if we have either text or attachments
|
|
922
1497
|
const hasText = text && text.trim().length > 0;
|
|
923
1498
|
const hasAttachments = this.pendingAttachments.length > 0;
|
|
@@ -925,14 +1500,14 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
925
1500
|
return;
|
|
926
1501
|
}
|
|
927
1502
|
// In empty state mode, just emit the data and let parent handle conversation creation
|
|
928
|
-
if (this.
|
|
1503
|
+
if (this.EmptyStateMode) {
|
|
929
1504
|
const attachmentsToEmit = [...this.pendingAttachments];
|
|
930
1505
|
this.pendingAttachments = [];
|
|
931
|
-
this.
|
|
932
|
-
this.
|
|
1506
|
+
this.MessageText = '';
|
|
1507
|
+
this.EmptyStateSubmit.emit({ text: text?.trim() || '', attachments: attachmentsToEmit });
|
|
933
1508
|
return;
|
|
934
1509
|
}
|
|
935
|
-
this.
|
|
1510
|
+
this.IsSending = true;
|
|
936
1511
|
// Store attachments locally since we'll clear them after send
|
|
937
1512
|
const attachmentsToSave = [...this.pendingAttachments];
|
|
938
1513
|
try {
|
|
@@ -944,12 +1519,12 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
944
1519
|
// separately when building AI messages - no need to add tokens to Message field
|
|
945
1520
|
if (attachmentsToSave.length > 0) {
|
|
946
1521
|
// Show upload indicator for attachments
|
|
947
|
-
this.
|
|
948
|
-
this.
|
|
949
|
-
this.
|
|
1522
|
+
this.IsUploadingAttachments = true;
|
|
1523
|
+
this.UploadingMessage = `Uploading ${attachmentsToSave.length} attachment${attachmentsToSave.length > 1 ? 's' : ''}...`;
|
|
1524
|
+
this.UploadStateChanged.emit({ isUploading: true, message: this.UploadingMessage });
|
|
950
1525
|
let attachmentRejection = null;
|
|
951
1526
|
try {
|
|
952
|
-
await this.attachmentService.saveAttachments(messageDetail.ID, attachmentsToSave, this.
|
|
1527
|
+
await this.attachmentService.saveAttachments(messageDetail.ID, attachmentsToSave, this.CurrentUser);
|
|
953
1528
|
}
|
|
954
1529
|
catch (attachmentError) {
|
|
955
1530
|
console.error('Failed to save attachments:', attachmentError);
|
|
@@ -958,8 +1533,8 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
958
1533
|
: 'Some attachments could not be saved';
|
|
959
1534
|
}
|
|
960
1535
|
finally {
|
|
961
|
-
this.
|
|
962
|
-
this.
|
|
1536
|
+
this.IsUploadingAttachments = false;
|
|
1537
|
+
this.UploadStateChanged.emit({ isUploading: false, message: '' });
|
|
963
1538
|
}
|
|
964
1539
|
// Plan §6: when attachments are rejected, the message itself must
|
|
965
1540
|
// not go through. Roll back the ConversationDetail and notify the
|
|
@@ -974,7 +1549,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
974
1549
|
catch (rollbackErr) {
|
|
975
1550
|
console.error('Failed to roll back conversation detail after attachment rejection:', rollbackErr);
|
|
976
1551
|
}
|
|
977
|
-
this.
|
|
1552
|
+
this.IsSending = false;
|
|
978
1553
|
return;
|
|
979
1554
|
}
|
|
980
1555
|
}
|
|
@@ -990,9 +1565,13 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
990
1565
|
this.handleSendError(error);
|
|
991
1566
|
}
|
|
992
1567
|
finally {
|
|
993
|
-
this.
|
|
1568
|
+
this.IsSending = false;
|
|
994
1569
|
}
|
|
995
1570
|
}
|
|
1571
|
+
/** @deprecated Use {@link OnTextSubmitted}. */
|
|
1572
|
+
async onTextSubmitted(text) {
|
|
1573
|
+
return this.OnTextSubmitted(text);
|
|
1574
|
+
}
|
|
996
1575
|
/**
|
|
997
1576
|
* Toggle sticky Plan Mode for THIS conversation (or the pending-new bucket on the
|
|
998
1577
|
* new-conversation composer). Writes through {@link PlanModePreference} — the
|
|
@@ -1001,12 +1580,12 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1001
1580
|
* until the user turns it off or approves a plan.
|
|
1002
1581
|
*/
|
|
1003
1582
|
TogglePlanMode() {
|
|
1004
|
-
PlanModePreference.Set(this.
|
|
1583
|
+
PlanModePreference.Set(this.ConversationId, !this.PlanModeEnabled);
|
|
1005
1584
|
}
|
|
1006
|
-
async
|
|
1007
|
-
if (!this.
|
|
1585
|
+
async OnSend() {
|
|
1586
|
+
if (!this.CanSend)
|
|
1008
1587
|
return;
|
|
1009
|
-
this.
|
|
1588
|
+
this.IsSending = true;
|
|
1010
1589
|
try {
|
|
1011
1590
|
const messageDetail = await this.createMessageDetail();
|
|
1012
1591
|
const saved = await messageDetail.Save();
|
|
@@ -1021,9 +1600,13 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1021
1600
|
this.handleSendError(error);
|
|
1022
1601
|
}
|
|
1023
1602
|
finally {
|
|
1024
|
-
this.
|
|
1603
|
+
this.IsSending = false;
|
|
1025
1604
|
}
|
|
1026
1605
|
}
|
|
1606
|
+
/** @deprecated Use {@link OnSend}. */
|
|
1607
|
+
async onSend() {
|
|
1608
|
+
return this.OnSend();
|
|
1609
|
+
}
|
|
1027
1610
|
/**
|
|
1028
1611
|
* Send a message with custom text WITHOUT modifying the visible messageText input
|
|
1029
1612
|
* Used for suggested responses and initial messages from empty state.
|
|
@@ -1035,7 +1618,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1035
1618
|
* `this.pendingAttachments` may not contain the attachment. Pass it in
|
|
1036
1619
|
* explicitly and we merge + dedupe (by `id`) before saving.
|
|
1037
1620
|
*/
|
|
1038
|
-
async
|
|
1621
|
+
async SendMessageWithText(text, extraAttachments) {
|
|
1039
1622
|
const merged = (() => {
|
|
1040
1623
|
if (!extraAttachments || extraAttachments.length === 0) {
|
|
1041
1624
|
return [...this.pendingAttachments];
|
|
@@ -1055,31 +1638,31 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1055
1638
|
if (!hasText && !hasAttachments) {
|
|
1056
1639
|
return false;
|
|
1057
1640
|
}
|
|
1058
|
-
if (this.
|
|
1641
|
+
if (this.IsSending) {
|
|
1059
1642
|
return false;
|
|
1060
1643
|
}
|
|
1061
|
-
this.
|
|
1644
|
+
this.IsSending = true;
|
|
1062
1645
|
const attachmentsToSave = merged;
|
|
1063
1646
|
try {
|
|
1064
|
-
const detail = await this.dataCache.createConversationDetail(this.
|
|
1065
|
-
detail.ConversationID = this.
|
|
1647
|
+
const detail = await this.dataCache.createConversationDetail(this.CurrentUser);
|
|
1648
|
+
detail.ConversationID = this.ConversationId;
|
|
1066
1649
|
detail.Message = text?.trim() || '';
|
|
1067
1650
|
detail.Role = 'User';
|
|
1068
|
-
detail.UserID = this.
|
|
1069
|
-
if (this.
|
|
1070
|
-
detail.ParentID = this.
|
|
1651
|
+
detail.UserID = this.CurrentUser.ID; // Set the user who sent the message
|
|
1652
|
+
if (this.ParentMessageId) {
|
|
1653
|
+
detail.ParentID = this.ParentMessageId;
|
|
1071
1654
|
}
|
|
1072
1655
|
const saved = await detail.Save();
|
|
1073
1656
|
if (saved) {
|
|
1074
1657
|
// Save attachments if any were pending
|
|
1075
1658
|
if (attachmentsToSave.length > 0) {
|
|
1076
1659
|
// Show upload indicator for attachments
|
|
1077
|
-
this.
|
|
1078
|
-
this.
|
|
1079
|
-
this.
|
|
1660
|
+
this.IsUploadingAttachments = true;
|
|
1661
|
+
this.UploadingMessage = `Uploading ${attachmentsToSave.length} attachment${attachmentsToSave.length > 1 ? 's' : ''}...`;
|
|
1662
|
+
this.UploadStateChanged.emit({ isUploading: true, message: this.UploadingMessage });
|
|
1080
1663
|
let attachmentRejection = null;
|
|
1081
1664
|
try {
|
|
1082
|
-
await this.attachmentService.saveAttachments(detail.ID, attachmentsToSave, this.
|
|
1665
|
+
await this.attachmentService.saveAttachments(detail.ID, attachmentsToSave, this.CurrentUser);
|
|
1083
1666
|
}
|
|
1084
1667
|
catch (attachmentError) {
|
|
1085
1668
|
console.error('Failed to save attachments:', attachmentError);
|
|
@@ -1088,8 +1671,8 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1088
1671
|
: 'Some attachments could not be saved';
|
|
1089
1672
|
}
|
|
1090
1673
|
finally {
|
|
1091
|
-
this.
|
|
1092
|
-
this.
|
|
1674
|
+
this.IsUploadingAttachments = false;
|
|
1675
|
+
this.UploadStateChanged.emit({ isUploading: false, message: '' });
|
|
1093
1676
|
}
|
|
1094
1677
|
// Plan §6: roll back the message when attachments are rejected so
|
|
1095
1678
|
// the user sees the rejection clearly instead of the agent answering
|
|
@@ -1102,7 +1685,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1102
1685
|
catch (rollbackErr) {
|
|
1103
1686
|
console.error('Failed to roll back conversation detail after attachment rejection:', rollbackErr);
|
|
1104
1687
|
}
|
|
1105
|
-
this.
|
|
1688
|
+
this.IsSending = false;
|
|
1106
1689
|
return false;
|
|
1107
1690
|
}
|
|
1108
1691
|
}
|
|
@@ -1112,10 +1695,10 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1112
1695
|
// The user-initiated send path (MessageInputBoxComponent.onSendClick)
|
|
1113
1696
|
// calls mentionEditor.clear() — we bypass that path here, so the chips
|
|
1114
1697
|
// would otherwise stay on screen after the message goes out.
|
|
1115
|
-
this.
|
|
1116
|
-
this.
|
|
1698
|
+
this.InputBox?.mentionEditor?.clear();
|
|
1699
|
+
this.MessageSent.emit(detail);
|
|
1117
1700
|
const mentionResult = this.parseMentionsFromMessage(detail.Message);
|
|
1118
|
-
const isFirstMessage = this.
|
|
1701
|
+
const isFirstMessage = this.ConversationHistory.length === 0;
|
|
1119
1702
|
await this.routeMessage(detail, mentionResult, isFirstMessage);
|
|
1120
1703
|
return true;
|
|
1121
1704
|
}
|
|
@@ -1129,20 +1712,24 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1129
1712
|
return false;
|
|
1130
1713
|
}
|
|
1131
1714
|
finally {
|
|
1132
|
-
this.
|
|
1715
|
+
this.IsSending = false;
|
|
1133
1716
|
}
|
|
1134
1717
|
}
|
|
1718
|
+
/** @deprecated Use {@link SendMessageWithText}. */
|
|
1719
|
+
async sendMessageWithText(text, extraAttachments) {
|
|
1720
|
+
return this.SendMessageWithText(text, extraAttachments);
|
|
1721
|
+
}
|
|
1135
1722
|
/**
|
|
1136
1723
|
* Creates and configures a new conversation detail message
|
|
1137
1724
|
*/
|
|
1138
1725
|
async createMessageDetail() {
|
|
1139
|
-
const detail = await this.dataCache.createConversationDetail(this.
|
|
1140
|
-
detail.ConversationID = this.
|
|
1141
|
-
detail.Message = this.
|
|
1726
|
+
const detail = await this.dataCache.createConversationDetail(this.CurrentUser);
|
|
1727
|
+
detail.ConversationID = this.ConversationId;
|
|
1728
|
+
detail.Message = this.MessageText.trim();
|
|
1142
1729
|
detail.Role = 'User';
|
|
1143
|
-
detail.UserID = this.
|
|
1144
|
-
if (this.
|
|
1145
|
-
detail.ParentID = this.
|
|
1730
|
+
detail.UserID = this.CurrentUser.ID; // Set the user who sent the message
|
|
1731
|
+
if (this.ParentMessageId) {
|
|
1732
|
+
detail.ParentID = this.ParentMessageId;
|
|
1146
1733
|
}
|
|
1147
1734
|
return detail;
|
|
1148
1735
|
}
|
|
@@ -1150,13 +1737,13 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1150
1737
|
* Creates and configures a new conversation detail message from provided text
|
|
1151
1738
|
*/
|
|
1152
1739
|
async createMessageDetailFromText(text) {
|
|
1153
|
-
const detail = await this.dataCache.createConversationDetail(this.
|
|
1154
|
-
detail.ConversationID = this.
|
|
1740
|
+
const detail = await this.dataCache.createConversationDetail(this.CurrentUser);
|
|
1741
|
+
detail.ConversationID = this.ConversationId;
|
|
1155
1742
|
detail.Message = text;
|
|
1156
1743
|
detail.Role = 'User';
|
|
1157
|
-
detail.UserID = this.
|
|
1158
|
-
if (this.
|
|
1159
|
-
detail.ParentID = this.
|
|
1744
|
+
detail.UserID = this.CurrentUser.ID; // Set the user who sent the message
|
|
1745
|
+
if (this.ParentMessageId) {
|
|
1746
|
+
detail.ParentID = this.ParentMessageId;
|
|
1160
1747
|
}
|
|
1161
1748
|
return detail;
|
|
1162
1749
|
}
|
|
@@ -1164,10 +1751,10 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1164
1751
|
* Handles successful message send - routes to appropriate agent
|
|
1165
1752
|
*/
|
|
1166
1753
|
async handleSuccessfulSend(messageDetail) {
|
|
1167
|
-
this.
|
|
1168
|
-
this.
|
|
1754
|
+
this.MessageSent.emit(messageDetail);
|
|
1755
|
+
this.MessageText = '';
|
|
1169
1756
|
const mentionResult = this.parseMentionsFromMessage(messageDetail.Message);
|
|
1170
|
-
const isFirstMessage = this.
|
|
1757
|
+
const isFirstMessage = this.ConversationHistory.length === 0;
|
|
1171
1758
|
await this.routeMessage(messageDetail, mentionResult, isFirstMessage);
|
|
1172
1759
|
this.refocusTextarea();
|
|
1173
1760
|
}
|
|
@@ -1179,9 +1766,13 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1179
1766
|
return mentionResult;
|
|
1180
1767
|
}
|
|
1181
1768
|
/**
|
|
1182
|
-
* Routes
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1769
|
+
* Routes a saved message to the agent that answers it — or to none.
|
|
1770
|
+
*
|
|
1771
|
+
* Routing picks the agent ({@link resolveAgentTurnTarget}): a tagged agent, then (under
|
|
1772
|
+
* `AgentReplyMode` `'Always'`) the last agent that answered, the conversation's pinned agent,
|
|
1773
|
+
* the host's default agent, and the conversation manager, each only if the host allows it.
|
|
1774
|
+
* {@link BeforeAgentTurn} is then fired once, before any reply row exists, and the turn runs on
|
|
1775
|
+
* MJ's path or through the host's {@link AgentTurnHandler}.
|
|
1185
1776
|
*/
|
|
1186
1777
|
async routeMessage(messageDetail, mentionResult, isFirstMessage) {
|
|
1187
1778
|
// A Plan Mode choice made on the new-conversation composer (no conversation yet) lives in a
|
|
@@ -1199,80 +1790,123 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1199
1790
|
this._pendingRequestedSkillIDs = mentionResult.skillMentions?.length
|
|
1200
1791
|
? mentionResult.skillMentions.map(m => m.id)
|
|
1201
1792
|
: this.collectRequestedSkillIDs();
|
|
1202
|
-
//
|
|
1203
|
-
|
|
1204
|
-
|
|
1793
|
+
// Naming is about the conversation, not the turn, so it doesn't wait on (or depend on) one.
|
|
1794
|
+
// It runs in the background: naming can take minutes to time out.
|
|
1795
|
+
if (isFirstMessage && this.AutoNameConversation) {
|
|
1796
|
+
void this.nameConversation(messageDetail.Message, messageDetail.ConversationID)
|
|
1797
|
+
.catch(error => console.error('Conversation naming failed:', error));
|
|
1798
|
+
}
|
|
1799
|
+
const target = this.resolveAgentTurnTarget(mentionResult);
|
|
1800
|
+
if (!target) {
|
|
1801
|
+
await this.finishWithoutAgentTurn(messageDetail, 'NoAgent');
|
|
1205
1802
|
return;
|
|
1206
1803
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
await this.handleAgentContinuity(messageDetail, lastAgentId, mentionResult, isFirstMessage);
|
|
1804
|
+
const turn = this.announceAgentTurn(messageDetail, target);
|
|
1805
|
+
if (!turn) {
|
|
1806
|
+
await this.finishWithoutAgentTurn(messageDetail, 'Declined');
|
|
1211
1807
|
return;
|
|
1212
1808
|
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1809
|
+
await this.runAgentTurn(messageDetail, mentionResult, turn);
|
|
1810
|
+
}
|
|
1811
|
+
/** The host's rules, as the routing functions take them. */
|
|
1812
|
+
get agentTurnRules() {
|
|
1813
|
+
return { ReplyMode: this.AgentReplyMode, AllowedAgentIDs: this.AllowedAgentIDs };
|
|
1814
|
+
}
|
|
1815
|
+
/** The agent each route would use for this conversation, before the host's rules apply. */
|
|
1816
|
+
agentTurnCandidates(mentionedAgentIds) {
|
|
1817
|
+
return {
|
|
1818
|
+
MentionedAgentIds: mentionedAgentIds,
|
|
1819
|
+
ContinuityAgentId: this.findLastNonSageAgentId(),
|
|
1820
|
+
ConversationDefaultAgentId: this.ConversationDefaultAgentId,
|
|
1821
|
+
HostDefaultAgentId: this.DefaultAgentId,
|
|
1822
|
+
ConversationManagerAgentId: this.ConverationManagerAgent?.ID ?? null
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1825
|
+
/** Picks the agent that answers this message and the route that chose it, or null for no turn. */
|
|
1826
|
+
resolveAgentTurnTarget(mentionResult) {
|
|
1827
|
+
const mentionedAgentIds = mentionResult.mentions.filter(m => m.type === 'agent').map(m => m.id);
|
|
1828
|
+
return ResolveAgentTurn(this.agentTurnCandidates(mentionedAgentIds), this.agentTurnRules, agentId => this.isKnownAgent(agentId));
|
|
1829
|
+
}
|
|
1830
|
+
/**
|
|
1831
|
+
* Fires {@link BeforeAgentTurn} for the turn routing picked — before any reply row exists —
|
|
1832
|
+
* and applies what its listeners decided. Returns the turn to run, or null when a listener
|
|
1833
|
+
* canceled it or redirected it to an agent this chat can't use.
|
|
1834
|
+
*/
|
|
1835
|
+
announceAgentTurn(userMessage, target) {
|
|
1836
|
+
const args = new BeforeAgentTurnEventArgs(userMessage.ConversationID, userMessage.Message ?? '', this.ApplicationId, { ...target, AgentName: this.agentNameFor(target.AgentId), UserMessageId: userMessage.ID });
|
|
1837
|
+
this.BeforeAgentTurn.emit(args);
|
|
1838
|
+
if (args.Cancel) {
|
|
1839
|
+
LogStatusEx({ message: `Agent turn canceled by a BeforeAgentTurn listener${args.CancelReason ? `: ${args.CancelReason}` : ''}` });
|
|
1840
|
+
return null;
|
|
1841
|
+
}
|
|
1842
|
+
const redirectAgentId = args.RedirectAgentId;
|
|
1843
|
+
if (!redirectAgentId || UUIDsEqual(redirectAgentId, target.AgentId)) {
|
|
1844
|
+
return target;
|
|
1845
|
+
}
|
|
1846
|
+
if (!IsAgentAllowed(redirectAgentId, this.AllowedAgentIDs) || !this.isKnownAgent(redirectAgentId)) {
|
|
1847
|
+
this.notifyAgentTurnProblem('That agent isn\'t available in this chat, so it didn\'t answer.', 'warning');
|
|
1848
|
+
return null;
|
|
1849
|
+
}
|
|
1850
|
+
return { AgentId: redirectAgentId, Route: 'Redirect' };
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* Settles a message that starts no agent turn — `MentionOnly` with no tagged agent, no allowed
|
|
1854
|
+
* agent left, or a turn declined in {@link BeforeAgentTurn}. Nothing new is written; the
|
|
1855
|
+
* person's own row is only confirmed Complete.
|
|
1856
|
+
*/
|
|
1857
|
+
async finishWithoutAgentTurn(userMessage, reason) {
|
|
1858
|
+
// Under the default rules a turn always has somewhere to go, so reaching here with no agent
|
|
1859
|
+
// means MJ's conversation manager failed to load. Say so rather than sit silent.
|
|
1860
|
+
if (reason === 'NoAgent' && this.AgentReplyMode === 'Always' && this.AllowedAgentIDs == null) {
|
|
1861
|
+
this.notifyAgentTurnProblem('No agent is available to answer this message.', 'error');
|
|
1220
1862
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
await this.handleAgentContinuity(messageDetail, this.defaultAgentId, mentionResult, isFirstMessage);
|
|
1863
|
+
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
1864
|
+
}
|
|
1865
|
+
/** Runs a turn that {@link BeforeAgentTurn} let through, on the host's handler or MJ's path. */
|
|
1866
|
+
async runAgentTurn(userMessage, mentionResult, turn) {
|
|
1867
|
+
const mention = turn.Route === 'Mention' ? this.findAgentMention(mentionResult, turn.AgentId) : null;
|
|
1868
|
+
if (this.AgentTurnHandler) {
|
|
1869
|
+
await this.runHostAgentTurn(this.AgentTurnHandler, userMessage, turn, mention);
|
|
1229
1870
|
return;
|
|
1230
1871
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
await this.executeRouteWithNaming(() => this.executeAgentContinuation(messageDetail, this.converationManagerAgent.ID, this.converationManagerAgent.Name || 'Sage', messageDetail.ConversationID, null, // Sage doesn't use payload continuity
|
|
1241
|
-
null, // Sage doesn't use artifact info
|
|
1242
|
-
sageConfigPreset // Pass the already-found config preset
|
|
1243
|
-
), messageDetail.Message, isFirstMessage, messageDetail.ConversationID);
|
|
1244
|
-
return;
|
|
1245
|
-
}
|
|
1872
|
+
if (mention) {
|
|
1873
|
+
await this.invokeAgentDirectly(userMessage, mention, userMessage.ConversationID);
|
|
1874
|
+
}
|
|
1875
|
+
else if (turn.Route === 'ConversationManager' || (turn.Route === 'Redirect' && this.isConversationManager(turn.AgentId))) {
|
|
1876
|
+
await this.runConversationManagerTurn(userMessage, mentionResult);
|
|
1877
|
+
}
|
|
1878
|
+
else {
|
|
1879
|
+
// Pinned and host defaults keep their direct call even when they name the manager, as before.
|
|
1880
|
+
await this.handleAgentContinuity(userMessage, turn.AgentId);
|
|
1246
1881
|
}
|
|
1247
|
-
// Priority 6: No context - use Sage with default config
|
|
1248
|
-
await this.handleNoAgentContext(messageDetail, mentionResult, isFirstMessage);
|
|
1249
1882
|
}
|
|
1250
1883
|
/**
|
|
1251
|
-
*
|
|
1884
|
+
* The tagged agent's mention, with its configuration preset. A mention saved without one
|
|
1885
|
+
* (legacy text format) takes the preset from its chip in the composer, when there is one.
|
|
1252
1886
|
*/
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1887
|
+
findAgentMention(mentionResult, agentId) {
|
|
1888
|
+
const mention = mentionResult.mentions.find(m => m.type === 'agent' && UUIDsEqual(m.id, agentId));
|
|
1889
|
+
if (!mention) {
|
|
1890
|
+
return null;
|
|
1891
|
+
}
|
|
1892
|
+
if (!mention.configurationId) {
|
|
1893
|
+
const chipData = this.InputBox?.getMentionChipsData() || [];
|
|
1894
|
+
const agentChip = chipData.find(chip => chip.id === mention.id && chip.type === 'agent');
|
|
1259
1895
|
if (agentChip?.presetId) {
|
|
1260
|
-
|
|
1896
|
+
mention.configurationId = agentChip.presetId;
|
|
1261
1897
|
}
|
|
1262
1898
|
}
|
|
1263
|
-
|
|
1264
|
-
//console.log(`🎯 Agent mention has configuration ID: ${agentMention.configurationId}`);
|
|
1265
|
-
}
|
|
1266
|
-
await this.executeRouteWithNaming(() => this.invokeAgentDirectly(messageDetail, agentMention, messageDetail.ConversationID), messageDetail.Message, isFirstMessage, messageDetail.ConversationID);
|
|
1899
|
+
return mention;
|
|
1267
1900
|
}
|
|
1268
1901
|
/**
|
|
1269
|
-
*
|
|
1902
|
+
* Continues with an agent chosen without a mention: the last agent that answered, the pinned
|
|
1903
|
+
* or host default agent, or a redirect.
|
|
1270
1904
|
*
|
|
1271
1905
|
* LATENCY OPTIMIZATION (PR #2309 / plans/agent-latency-optimization.md — Opt #1):
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1275
|
-
*
|
|
1906
|
+
* This used to make a separate LLM call via checkContinuityIntent() to decide whether the
|
|
1907
|
+
* user's new message was still directed at the previous agent or should be routed to Sage.
|
|
1908
|
+
* That call added ~300ms of latency on every message in a conversation with an active agent —
|
|
1909
|
+
* the single largest source of non-inference overhead on the client.
|
|
1276
1910
|
*
|
|
1277
1911
|
* The heuristic replacement is simple: if a previous non-Sage agent exists, always continue
|
|
1278
1912
|
* with it. The user can @mention a different agent (or Sage) to explicitly switch. This is
|
|
@@ -1284,49 +1918,149 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1284
1918
|
* when browser-local inference is fast enough (~20-50ms) to do this without blocking the
|
|
1285
1919
|
* user. See PR #2309 for the full discussion.
|
|
1286
1920
|
*/
|
|
1287
|
-
async handleAgentContinuity(messageDetail,
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
/**
|
|
1314
|
-
* Handles routing when there's no previous agent context
|
|
1315
|
-
*/
|
|
1316
|
-
async handleNoAgentContext(messageDetail, mentionResult, isFirstMessage) {
|
|
1317
|
-
await this.executeRouteWithNaming(() => this.processMessageThroughAgent(messageDetail, mentionResult), messageDetail.Message, isFirstMessage, messageDetail.ConversationID);
|
|
1318
|
-
}
|
|
1319
|
-
/**
|
|
1320
|
-
* Finds the last agent ID that isn't Sage
|
|
1921
|
+
async handleAgentContinuity(messageDetail, agentId) {
|
|
1922
|
+
await this.continueWithAgent(messageDetail, agentId, messageDetail.ConversationID, undefined // artifact version targeting unavailable without intent check
|
|
1923
|
+
);
|
|
1924
|
+
}
|
|
1925
|
+
/**
|
|
1926
|
+
* The conversation manager's turn. When an earlier message @mentioned the manager with a
|
|
1927
|
+
* configuration preset, the preset keeps applying and the manager answers directly;
|
|
1928
|
+
* otherwise it evaluates the message and may delegate.
|
|
1929
|
+
*/
|
|
1930
|
+
async runConversationManagerTurn(messageDetail, mentionResult) {
|
|
1931
|
+
const manager = this.ConverationManagerAgent;
|
|
1932
|
+
const managerPreset = manager?.ID && messageDetail.ConversationID
|
|
1933
|
+
? await this.agentService.FindConfigurationPresetForAgent(messageDetail.ConversationID, manager.ID)
|
|
1934
|
+
: undefined;
|
|
1935
|
+
if (manager?.ID && managerPreset) {
|
|
1936
|
+
await this.executeAgentContinuation(messageDetail, manager.ID, manager.Name || 'Sage', messageDetail.ConversationID, null, // Sage doesn't use payload continuity
|
|
1937
|
+
null, // Sage doesn't use artifact info
|
|
1938
|
+
managerPreset // Pass the already-found config preset
|
|
1939
|
+
);
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
await this.processMessageThroughAgent(messageDetail, mentionResult);
|
|
1943
|
+
}
|
|
1944
|
+
/**
|
|
1945
|
+
* The newest reply from an agent other than the conversation manager — among the replies a
|
|
1946
|
+
* turn may read, so from {@link AgentHistoryFrom} onward when it's set.
|
|
1321
1947
|
*/
|
|
1322
|
-
|
|
1323
|
-
|
|
1948
|
+
findLastNonSageReply() {
|
|
1949
|
+
return this.ConversationHistory
|
|
1324
1950
|
.slice()
|
|
1325
1951
|
.reverse()
|
|
1326
1952
|
.find(msg => msg.Role === 'AI' &&
|
|
1327
|
-
msg.AgentID &&
|
|
1328
|
-
!UUIDsEqual(msg.AgentID, this.
|
|
1329
|
-
|
|
1953
|
+
!!msg.AgentID &&
|
|
1954
|
+
!UUIDsEqual(msg.AgentID, this.ConverationManagerAgent?.ID) &&
|
|
1955
|
+
this.isWithinHistoryFloor(msg)) ?? null;
|
|
1956
|
+
}
|
|
1957
|
+
/**
|
|
1958
|
+
* Finds the last agent ID that isn't Sage (see {@link findLastNonSageReply}).
|
|
1959
|
+
*/
|
|
1960
|
+
findLastNonSageAgentId() {
|
|
1961
|
+
return this.findLastNonSageReply()?.AgentID || null;
|
|
1962
|
+
}
|
|
1963
|
+
/** True when a row was written at or after {@link AgentHistoryFrom}; always true without one. */
|
|
1964
|
+
isWithinHistoryFloor(detail) {
|
|
1965
|
+
const floor = this.AgentHistoryFrom;
|
|
1966
|
+
if (!floor) {
|
|
1967
|
+
return true;
|
|
1968
|
+
}
|
|
1969
|
+
const createdAt = detail.__mj_CreatedAt;
|
|
1970
|
+
return createdAt != null && new Date(createdAt).getTime() >= floor.getTime();
|
|
1971
|
+
}
|
|
1972
|
+
/** True when the agent is in the client's agent catalog. */
|
|
1973
|
+
isKnownAgent(agentId) {
|
|
1974
|
+
return AIEngineBase.Instance.Agents.some(a => UUIDsEqual(a.ID, agentId));
|
|
1975
|
+
}
|
|
1976
|
+
/** The agent's name, when the client's agent catalog has it. */
|
|
1977
|
+
agentNameFor(agentId) {
|
|
1978
|
+
return AIEngineBase.Instance.Agents.find(a => UUIDsEqual(a.ID, agentId))?.Name ?? null;
|
|
1979
|
+
}
|
|
1980
|
+
/** The ID of the agent with this name, or null when there is none. */
|
|
1981
|
+
agentIdByName(agentName) {
|
|
1982
|
+
return AIEngineBase.Instance.Agents.find(a => a.Name === agentName)?.ID ?? null;
|
|
1983
|
+
}
|
|
1984
|
+
/** True when the agent is MJ's conversation manager. */
|
|
1985
|
+
isConversationManager(agentId) {
|
|
1986
|
+
return !!this.ConverationManagerAgent?.ID && UUIDsEqual(agentId, this.ConverationManagerAgent.ID);
|
|
1987
|
+
}
|
|
1988
|
+
/** Shows the person why an agent turn didn't happen, or didn't finish. */
|
|
1989
|
+
notifyAgentTurnProblem(message, style) {
|
|
1990
|
+
MJNotificationService.Instance?.CreateSimpleNotification(message, style, 5000);
|
|
1991
|
+
}
|
|
1992
|
+
/**
|
|
1993
|
+
* Refuses agents the host doesn't allow — named by the conversation manager's delegation or
|
|
1994
|
+
* by a workflow it planned — and settles the person's message.
|
|
1995
|
+
*/
|
|
1996
|
+
async refuseDisallowedAgents(userMessage, agentNames) {
|
|
1997
|
+
const subject = agentNames.join(', ');
|
|
1998
|
+
this.notifyAgentTurnProblem(agentNames.length === 1
|
|
1999
|
+
? `${subject} isn't available in this chat, so it didn't run.`
|
|
2000
|
+
: `${subject} aren't available in this chat, so they didn't run.`, 'warning');
|
|
2001
|
+
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
2002
|
+
}
|
|
2003
|
+
/**
|
|
2004
|
+
* Runs the turn through the host's {@link AgentTurnHandler} instead of MJ's path. Nothing is
|
|
2005
|
+
* written here: the host writes the reply rows and reports them, and each is shown like a row
|
|
2006
|
+
* MJ wrote — one still In-Progress is followed like any other in-progress reply.
|
|
2007
|
+
*/
|
|
2008
|
+
async runHostAgentTurn(handler, userMessage, turn, mention) {
|
|
2009
|
+
const result = await this.callAgentTurnHandler(handler, this.buildAgentTurnRequest(userMessage, turn, mention));
|
|
2010
|
+
if (!result.Success) {
|
|
2011
|
+
this.notifyAgentTurnProblem(result.ErrorMessage || 'The agent could not answer this message.', 'error');
|
|
2012
|
+
}
|
|
2013
|
+
else {
|
|
2014
|
+
await this.showHostTurnRows(result.ReplyDetailIds ?? []);
|
|
2015
|
+
}
|
|
2016
|
+
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
2017
|
+
if (result.Success && result.Result) {
|
|
2018
|
+
this.emitAfterAgentTurn(userMessage.ConversationID, result.Result, result.AgentRunId);
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
/** Calls the host's handler; a throw is reported as a failed turn, never swallowed. */
|
|
2022
|
+
async callAgentTurnHandler(handler, request) {
|
|
2023
|
+
try {
|
|
2024
|
+
return await handler(request);
|
|
2025
|
+
}
|
|
2026
|
+
catch (error) {
|
|
2027
|
+
console.error('AgentTurnHandler failed:', error);
|
|
2028
|
+
return { Success: false, ErrorMessage: error instanceof Error ? error.message : String(error) };
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
/** What the host's handler is told about the turn. */
|
|
2032
|
+
buildAgentTurnRequest(userMessage, turn, mention) {
|
|
2033
|
+
return {
|
|
2034
|
+
ConversationId: userMessage.ConversationID,
|
|
2035
|
+
UserMessageId: userMessage.ID,
|
|
2036
|
+
MessageText: userMessage.Message ?? '',
|
|
2037
|
+
AgentId: turn.AgentId,
|
|
2038
|
+
AgentName: this.agentNameFor(turn.AgentId),
|
|
2039
|
+
Route: turn.Route,
|
|
2040
|
+
ApplicationId: this.ApplicationId,
|
|
2041
|
+
AppContext: this.AppContext,
|
|
2042
|
+
AgentHistoryFrom: this.AgentHistoryFrom,
|
|
2043
|
+
// A mention carries its own preset (or none); every other route follows the header picker.
|
|
2044
|
+
ConfigurationPresetId: turn.Route === 'Mention' ? (mention?.configurationId ?? null) : this.AgentConfigurationPresetId,
|
|
2045
|
+
RequestedSkillIDs: [...this._pendingRequestedSkillIDs],
|
|
2046
|
+
PlanMode: this.PlanModeEnabled
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
2049
|
+
/** Shows the rows a host's handler reported for its turn, oldest first. */
|
|
2050
|
+
async showHostTurnRows(detailIds) {
|
|
2051
|
+
for (const detailId of detailIds) {
|
|
2052
|
+
const detail = await this.dataCache.getConversationDetail(detailId, this.CurrentUser);
|
|
2053
|
+
if (detail) {
|
|
2054
|
+
this.MessageSent.emit(detail);
|
|
2055
|
+
}
|
|
2056
|
+
else {
|
|
2057
|
+
console.warn(`AgentTurnHandler reported conversation detail ${detailId}, but it could not be loaded`);
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
/** Fires {@link AfterAgentTurn} for a turn that succeeded. */
|
|
2062
|
+
emitAfterAgentTurn(conversationId, result, agentRunId) {
|
|
2063
|
+
this.AfterAgentTurn.emit(new AfterAgentTurnEventArgs(conversationId, agentRunId ?? result.agentRun?.ID ?? '', result));
|
|
1330
2064
|
}
|
|
1331
2065
|
/**
|
|
1332
2066
|
* Checks if message should continue with the previous agent
|
|
@@ -1344,17 +2078,17 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1344
2078
|
};
|
|
1345
2079
|
}
|
|
1346
2080
|
// Emit event to show temporary "Analyzing intent..." message in conversation
|
|
1347
|
-
this.
|
|
2081
|
+
this.IntentCheckStarted.emit({ conversationId: this.ConversationId });
|
|
1348
2082
|
try {
|
|
1349
2083
|
// The pre-loaded artifact/agent-run maps are no longer passed: they are scoped to the
|
|
1350
2084
|
// loaded transcript window, and the service now queries for this agent's artifacts so
|
|
1351
2085
|
// the classifier reasons over the whole conversation. A conversation id is what it
|
|
1352
2086
|
// needs instead, and without one there is nothing to query.
|
|
1353
|
-
if (!this.
|
|
2087
|
+
if (!this.ConversationId) {
|
|
1354
2088
|
console.warn('⚠️ No conversation id available for intent check');
|
|
1355
2089
|
return { decision: 'UNSURE', reasoning: 'Conversation not available' };
|
|
1356
2090
|
}
|
|
1357
|
-
const intent = await this.agentService.checkAgentContinuityIntent(this.
|
|
2091
|
+
const intent = await this.agentService.checkAgentContinuityIntent(this.ConversationId, agentId, message, this.ConversationHistory);
|
|
1358
2092
|
return intent;
|
|
1359
2093
|
}
|
|
1360
2094
|
catch (error) {
|
|
@@ -1363,25 +2097,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1363
2097
|
}
|
|
1364
2098
|
finally {
|
|
1365
2099
|
// Emit event to remove temporary intent checking message
|
|
1366
|
-
this.
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
/**
|
|
1370
|
-
* Executes a routing function, optionally with conversation naming for first message
|
|
1371
|
-
*
|
|
1372
|
-
* IMPORTANT: Conversation naming runs asynchronously in the background and does NOT
|
|
1373
|
-
* block the agent invocation. This prevents UI blocking if naming times out.
|
|
1374
|
-
*/
|
|
1375
|
-
async executeRouteWithNaming(routeFunction, userMessage, isFirstMessage, conversationId) {
|
|
1376
|
-
if (isFirstMessage) {
|
|
1377
|
-
// Fire conversation naming in background (don't await)
|
|
1378
|
-
// This prevents 2+ minute UI blocking if naming times out
|
|
1379
|
-
this.nameConversation(userMessage, conversationId);
|
|
1380
|
-
// Execute route immediately (don't wait for naming)
|
|
1381
|
-
await routeFunction();
|
|
1382
|
-
}
|
|
1383
|
-
else {
|
|
1384
|
-
await routeFunction();
|
|
2100
|
+
this.IntentCheckCompleted.emit({ conversationId: this.ConversationId });
|
|
1385
2101
|
}
|
|
1386
2102
|
}
|
|
1387
2103
|
/**
|
|
@@ -1389,8 +2105,8 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1389
2105
|
*/
|
|
1390
2106
|
refocusTextarea() {
|
|
1391
2107
|
setTimeout(() => {
|
|
1392
|
-
if (this.
|
|
1393
|
-
this.
|
|
2108
|
+
if (this.InputBox) {
|
|
2109
|
+
this.InputBox.focus();
|
|
1394
2110
|
}
|
|
1395
2111
|
}, 100);
|
|
1396
2112
|
}
|
|
@@ -1450,7 +2166,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1450
2166
|
// CRITICAL FIX: Emit FULL agent run object for incremental updates
|
|
1451
2167
|
// This contains live timestamps, status, and other fields that change during execution
|
|
1452
2168
|
if (progressAgentRun || progressAgentRunId) {
|
|
1453
|
-
this.
|
|
2169
|
+
this.AgentRunUpdate.emit({
|
|
1454
2170
|
conversationId: conversationDetail.ConversationID,
|
|
1455
2171
|
conversationDetailId: conversationDetail.ID,
|
|
1456
2172
|
agentRun: progressAgentRun,
|
|
@@ -1460,7 +2176,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1460
2176
|
else if (progressAgentRunId && !capturedAgentRunId) {
|
|
1461
2177
|
// Fallback: If we don't have the full object but have the ID, emit agentRunDetected
|
|
1462
2178
|
// This will trigger a database query to load the agent run
|
|
1463
|
-
this.
|
|
2179
|
+
this.AgentRunDetected.emit({
|
|
1464
2180
|
conversationId: conversationDetail.ConversationID,
|
|
1465
2181
|
conversationDetailId: conversationDetail.ID,
|
|
1466
2182
|
agentRunId: progressAgentRunId
|
|
@@ -1470,7 +2186,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1470
2186
|
conversationDetail.Message = progressText;
|
|
1471
2187
|
// Server now saves progress - client only updates in-memory and emits for UI
|
|
1472
2188
|
// (Prevents race condition where client's late save overwrites server's final Status)
|
|
1473
|
-
this.
|
|
2189
|
+
this.MessageSent.emit(conversationDetail);
|
|
1474
2190
|
}
|
|
1475
2191
|
}
|
|
1476
2192
|
}
|
|
@@ -1481,7 +2197,8 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1481
2197
|
}
|
|
1482
2198
|
/**
|
|
1483
2199
|
* Process the message through agents (multi-stage: Sage -> possible sub-agent)
|
|
1484
|
-
* Only called when there's no @mention and no implicit agent context
|
|
2200
|
+
* Only called when there's no @mention and no implicit agent context.
|
|
2201
|
+
* {@link BeforeAgentTurn} has already fired — routing announces the turn before any row exists.
|
|
1485
2202
|
*/
|
|
1486
2203
|
async processMessageThroughAgent(userMessage, mentionResult) {
|
|
1487
2204
|
let taskId = null;
|
|
@@ -1491,7 +2208,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1491
2208
|
const conversationId = userMessage.ConversationID;
|
|
1492
2209
|
try {
|
|
1493
2210
|
// Create AI message for Sage BEFORE invoking
|
|
1494
|
-
conversationManagerMessage = await this.dataCache.createConversationDetail(this.
|
|
2211
|
+
conversationManagerMessage = await this.dataCache.createConversationDetail(this.CurrentUser);
|
|
1495
2212
|
conversationManagerMessage.ConversationID = conversationId;
|
|
1496
2213
|
conversationManagerMessage.Role = 'AI';
|
|
1497
2214
|
conversationManagerMessage.Message = '⏳ Starting...';
|
|
@@ -1499,11 +2216,11 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1499
2216
|
conversationManagerMessage.Status = 'In-Progress';
|
|
1500
2217
|
conversationManagerMessage.HiddenToUser = false;
|
|
1501
2218
|
// Use the preloaded Sage agent instead of looking it up
|
|
1502
|
-
if (this.
|
|
1503
|
-
conversationManagerMessage.AgentID = this.
|
|
2219
|
+
if (this.ConverationManagerAgent?.ID) {
|
|
2220
|
+
conversationManagerMessage.AgentID = this.ConverationManagerAgent.ID;
|
|
1504
2221
|
}
|
|
1505
2222
|
await conversationManagerMessage.Save();
|
|
1506
|
-
this.
|
|
2223
|
+
this.MessageSent.emit(conversationManagerMessage);
|
|
1507
2224
|
// Use Sage to evaluate and route
|
|
1508
2225
|
// Stage 1: Sage evaluates the message
|
|
1509
2226
|
taskId = this.activeTasks.add({
|
|
@@ -1512,39 +2229,22 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1512
2229
|
relatedMessageId: userMessage.ID,
|
|
1513
2230
|
conversationDetailId: conversationManagerMessage.ID,
|
|
1514
2231
|
conversationId,
|
|
1515
|
-
conversationName: this.
|
|
2232
|
+
conversationName: this.ConversationName
|
|
1516
2233
|
});
|
|
1517
|
-
|
|
1518
|
-
//
|
|
1519
|
-
//
|
|
1520
|
-
|
|
1521
|
-
// subscriber's final answer.
|
|
1522
|
-
const beforeEvent = new BeforeAgentTurnEventArgs(conversationId, userMessage.Message ?? '', this.applicationId);
|
|
1523
|
-
this.beforeAgentTurn.emit(beforeEvent);
|
|
1524
|
-
if (beforeEvent.Cancel) {
|
|
1525
|
-
// Mark the conversation-manager message as canceled + clear its task so the
|
|
1526
|
-
// UI doesn't show a forever-pending spinner. afterAgentTurn is NOT emitted.
|
|
1527
|
-
await this.updateConversationDetail(conversationManagerMessage, beforeEvent.CancelReason ?? '⛔ Turn canceled before agent invocation', 'Error');
|
|
1528
|
-
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
1529
|
-
this.cleanupCompletionTimestamp(conversationManagerMessage.ID);
|
|
1530
|
-
if (taskId) {
|
|
1531
|
-
this.activeTasks.remove(taskId);
|
|
1532
|
-
taskId = null;
|
|
1533
|
-
}
|
|
1534
|
-
return;
|
|
1535
|
-
}
|
|
1536
|
-
const result = await this.agentService.processMessage(conversationId, userMessage, this.conversationHistory, conversationManagerMessage.ID, this.createProgressCallback(conversationManagerMessage, 'Sage'), this.appContext, this.PlanModeEnabled, // per-request Plan Mode toggle
|
|
1537
|
-
this._pendingRequestedSkillIDs);
|
|
2234
|
+
const result = await this.agentService.ProcessMessage(conversationId, userMessage, this.ConversationHistory, conversationManagerMessage.ID, this.createProgressCallback(conversationManagerMessage, 'Sage'), this.AppContext, this.PlanModeEnabled, // per-request Plan Mode toggle
|
|
2235
|
+
this._pendingRequestedSkillIDs, // user-requested skills (/skill mentions)
|
|
2236
|
+
this.AllowedAgentIDs, // the agents the manager may delegate to
|
|
2237
|
+
this.AgentHistoryFrom);
|
|
1538
2238
|
// Emit afterAgentTurn on the happy path only — the error/failure branch
|
|
1539
2239
|
// immediately below handles its own cleanup and skips this emit.
|
|
1540
2240
|
if (result && result.success) {
|
|
1541
|
-
this.
|
|
2241
|
+
this.emitAfterAgentTurn(conversationId, result);
|
|
1542
2242
|
}
|
|
1543
2243
|
// Task will be removed automatically in markMessageComplete()
|
|
1544
2244
|
// DO NOT remove here - agent may still be streaming/processing
|
|
1545
2245
|
taskId = null; // Clear reference but don't remove from service
|
|
1546
2246
|
if (!result || !result.success) {
|
|
1547
|
-
await this.applyAgentFailureToDetail(conversationManagerMessage, userMessage, this.
|
|
2247
|
+
await this.applyAgentFailureToDetail(conversationManagerMessage, userMessage, this.ConverationManagerAgent?.Name || 'Sage', result, 'failed');
|
|
1548
2248
|
console.warn('⚠️ Sage failed:', agentFailureMessage(result, 'Agent evaluation failed'));
|
|
1549
2249
|
this.cleanupCompletionTimestamp(conversationManagerMessage.ID);
|
|
1550
2250
|
return;
|
|
@@ -1576,7 +2276,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1576
2276
|
// Server already created artifacts - just emit event to trigger UI reload
|
|
1577
2277
|
if (result.payload && Object.keys(result.payload).length > 0) {
|
|
1578
2278
|
this.emitArtifactReload(conversationManagerMessage);
|
|
1579
|
-
this.
|
|
2279
|
+
this.MessageSent.emit(conversationManagerMessage);
|
|
1580
2280
|
}
|
|
1581
2281
|
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
1582
2282
|
// Remove CM from active tasks
|
|
@@ -1595,7 +2295,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1595
2295
|
conversationManagerMessage.HiddenToUser = false;
|
|
1596
2296
|
// use update helper to ensure that if there is a race condition with more streaming updates we don't allow that to override this final message
|
|
1597
2297
|
await this.updateConversationDetail(conversationManagerMessage, result.agentRun.Message, 'Complete', result);
|
|
1598
|
-
this.
|
|
2298
|
+
this.MessageSent.emit(conversationManagerMessage);
|
|
1599
2299
|
// Clean up completion timestamp after delay
|
|
1600
2300
|
this.cleanupCompletionTimestamp(conversationManagerMessage.ID);
|
|
1601
2301
|
}
|
|
@@ -1606,7 +2306,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1606
2306
|
conversationManagerMessage.HiddenToUser = true;
|
|
1607
2307
|
// use update helper to ensure that if there is a race condition with more streaming updates we don't allow that to override this final message
|
|
1608
2308
|
await this.updateConversationDetail(conversationManagerMessage, conversationManagerMessage.Message, 'Complete', result);
|
|
1609
|
-
this.
|
|
2309
|
+
this.MessageSent.emit(conversationManagerMessage);
|
|
1610
2310
|
await this.handleSilentObservation(userMessage, conversationId);
|
|
1611
2311
|
// Clean up completion timestamp after delay
|
|
1612
2312
|
this.cleanupCompletionTimestamp(conversationManagerMessage.ID);
|
|
@@ -1666,11 +2366,18 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1666
2366
|
const taskGraph = managerResult.payload?.taskGraph;
|
|
1667
2367
|
if (!taskGraph)
|
|
1668
2368
|
return;
|
|
2369
|
+
// The host's allowed list holds for every agent step of the plan, not only for a single
|
|
2370
|
+
// delegation: a workflow naming an agent the chat doesn't allow is not submitted at all.
|
|
2371
|
+
const disallowedAgents = FindDisallowedTaskGraphAgents(Array.isArray(taskGraph.tasks) ? taskGraph.tasks : [], this.AllowedAgentIDs, agentName => this.agentIdByName(agentName));
|
|
2372
|
+
if (disallowedAgents.length > 0) {
|
|
2373
|
+
await this.refuseDisallowedAgents(userMessage, disallowedAgents);
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
1669
2376
|
const workflowName = taskGraph.workflowName || 'Workflow';
|
|
1670
2377
|
const reasoning = taskGraph.reasoning || 'Executing multi-step workflow';
|
|
1671
2378
|
const taskCount = Array.isArray(taskGraph.tasks) ? taskGraph.tasks.length : 0;
|
|
1672
2379
|
// A message the user can watch. Progress frames from the dispatcher land against this ID.
|
|
1673
|
-
const taskExecutionMessage = await this.dataCache.createConversationDetail(this.
|
|
2380
|
+
const taskExecutionMessage = await this.dataCache.createConversationDetail(this.CurrentUser);
|
|
1674
2381
|
taskExecutionMessage.ConversationID = conversationId;
|
|
1675
2382
|
taskExecutionMessage.Role = 'AI';
|
|
1676
2383
|
taskExecutionMessage.Message = `⏳ **${workflowName}**\n\n${reasoning}\n\nSubmitting ${taskCount} task(s)…`;
|
|
@@ -1678,7 +2385,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1678
2385
|
taskExecutionMessage.Status = 'In-Progress';
|
|
1679
2386
|
taskExecutionMessage.HiddenToUser = false;
|
|
1680
2387
|
await taskExecutionMessage.Save();
|
|
1681
|
-
this.
|
|
2388
|
+
this.MessageSent.emit(taskExecutionMessage);
|
|
1682
2389
|
const callback = this.createMessageProgressCallback(taskExecutionMessage.ID);
|
|
1683
2390
|
this.registeredCallbacks.set(taskExecutionMessage.ID, callback);
|
|
1684
2391
|
this.streamingService.registerMessageCallback(taskExecutionMessage.ID, callback);
|
|
@@ -1728,7 +2435,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1728
2435
|
await convoDetail.Load(convoDetail.ID);
|
|
1729
2436
|
if (convoDetail.Status === 'Complete' || convoDetail.Status === 'Error') {
|
|
1730
2437
|
this.markMessageComplete(convoDetail);
|
|
1731
|
-
this.
|
|
2438
|
+
this.MessageSent.emit(convoDetail);
|
|
1732
2439
|
return;
|
|
1733
2440
|
}
|
|
1734
2441
|
}
|
|
@@ -1755,7 +2462,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1755
2462
|
await convoDetail.Save();
|
|
1756
2463
|
if (convoDetail.Message === message && convoDetail.Status === status) {
|
|
1757
2464
|
done = true;
|
|
1758
|
-
this.
|
|
2465
|
+
this.MessageSent.emit(convoDetail);
|
|
1759
2466
|
}
|
|
1760
2467
|
else {
|
|
1761
2468
|
console.warn(` ⚠️ ConversationDetail update attempt ${attempts + 1} did not persist. ${attempts + 1 < maxAttempts ? 'Retrying...' : 'Giving up.'}`);
|
|
@@ -1778,10 +2485,10 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1778
2485
|
* Direction, not on Visibility.
|
|
1779
2486
|
*/
|
|
1780
2487
|
async loadPreviousPayloadForAgent(agentId) {
|
|
1781
|
-
if (!this.
|
|
2488
|
+
if (!this.ConversationId) {
|
|
1782
2489
|
return { payload: null, artifactInfo: null };
|
|
1783
2490
|
}
|
|
1784
|
-
const source = await this.agentService.FindLatestAgentOutputVersion(this.
|
|
2491
|
+
const source = await this.agentService.FindLatestAgentOutputVersion(this.ConversationId, agentId, this.AgentHistoryFrom);
|
|
1785
2492
|
if (!source || source.payload == null) {
|
|
1786
2493
|
console.log(`📦 No previous payload found for agent ${agentId}`);
|
|
1787
2494
|
return { payload: null, artifactInfo: null };
|
|
@@ -1809,8 +2516,14 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1809
2516
|
try {
|
|
1810
2517
|
// Look up the agent to get its ID
|
|
1811
2518
|
const agent = AIEngineBase.Instance.Agents.find(a => a.Name === agentName);
|
|
2519
|
+
// The manager routes only among the allowed agents, but its answer is model output: hold
|
|
2520
|
+
// the host's list here too, before any row is written for the delegate.
|
|
2521
|
+
if (this.AllowedAgentIDs != null && !IsAgentAllowed(agent?.ID, this.AllowedAgentIDs)) {
|
|
2522
|
+
await this.refuseDisallowedAgents(userMessage, [agentName]);
|
|
2523
|
+
return;
|
|
2524
|
+
}
|
|
1812
2525
|
// Create AI response message BEFORE invoking agent (for duration tracking)
|
|
1813
|
-
agentResponseMessage = await this.dataCache.createConversationDetail(this.
|
|
2526
|
+
agentResponseMessage = await this.dataCache.createConversationDetail(this.CurrentUser);
|
|
1814
2527
|
agentResponseMessage.ConversationID = conversationId;
|
|
1815
2528
|
agentResponseMessage.Role = 'AI';
|
|
1816
2529
|
agentResponseMessage.Message = '⏳ Starting...'; // Initial message
|
|
@@ -1823,7 +2536,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1823
2536
|
}
|
|
1824
2537
|
// Save the record to establish __mj_CreatedAt timestamp
|
|
1825
2538
|
await agentResponseMessage.Save();
|
|
1826
|
-
this.
|
|
2539
|
+
this.MessageSent.emit(agentResponseMessage);
|
|
1827
2540
|
// Add sub-agent to active tasks
|
|
1828
2541
|
const newTaskId = this.activeTasks.add({
|
|
1829
2542
|
agentName: agentName,
|
|
@@ -1831,7 +2544,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1831
2544
|
relatedMessageId: userMessage.ID,
|
|
1832
2545
|
conversationDetailId: agentResponseMessage.ID,
|
|
1833
2546
|
conversationId,
|
|
1834
|
-
conversationName: this.
|
|
2547
|
+
conversationName: this.ConversationName
|
|
1835
2548
|
});
|
|
1836
2549
|
// Load previous payload if agent has been invoked before
|
|
1837
2550
|
const { payload: previousPayload, artifactInfo } = agent?.ID
|
|
@@ -1842,11 +2555,12 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1842
2555
|
? await this.agentService.FindConfigurationPresetForAgent(conversationId, agent.ID)
|
|
1843
2556
|
: undefined;
|
|
1844
2557
|
// Invoke the sub-agent with progress callback
|
|
1845
|
-
const subResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.
|
|
2558
|
+
const subResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.ConversationHistory, reasoning, agentResponseMessage.ID, previousPayload, // Pass previous payload for continuity
|
|
1846
2559
|
this.createProgressCallback(agentResponseMessage, agentName), artifactInfo?.artifactId, artifactInfo?.versionId, configurationPresetId, // Pass configuration from previous @mention for continuity
|
|
1847
|
-
this.
|
|
2560
|
+
this.AppContext, // Embedder-supplied app/form context
|
|
1848
2561
|
this.PlanModeEnabled, // per-request Plan Mode toggle
|
|
1849
|
-
this._pendingRequestedSkillIDs)
|
|
2562
|
+
this._pendingRequestedSkillIDs, // user-requested skills (/skill mentions)
|
|
2563
|
+
this.AgentHistoryFrom);
|
|
1850
2564
|
// Task will be removed automatically in markMessageComplete() when status changes to Complete/Error
|
|
1851
2565
|
// DO NOT remove here - allows UI to show task during entire execution
|
|
1852
2566
|
if (subResult && subResult.success) {
|
|
@@ -1860,7 +2574,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1860
2574
|
// artifacts even when the result payload is empty (e.g., remote stage server).
|
|
1861
2575
|
// onArtifactCreated will reload from DB and discover any artifacts that exist.
|
|
1862
2576
|
this.emitArtifactReload(agentResponseMessage);
|
|
1863
|
-
this.
|
|
2577
|
+
this.MessageSent.emit(agentResponseMessage);
|
|
1864
2578
|
// Mark user message as complete
|
|
1865
2579
|
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
1866
2580
|
}
|
|
@@ -1877,11 +2591,12 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1877
2591
|
// Update the existing agentResponseMessage to show retry status
|
|
1878
2592
|
await this.updateConversationDetail(agentResponseMessage, "Retrying...", agentResponseMessage.Status);
|
|
1879
2593
|
// Retry the sub-agent (reuse previously loaded payload and config from first attempt)
|
|
1880
|
-
const retryResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.
|
|
2594
|
+
const retryResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.ConversationHistory, reasoning, agentResponseMessage.ID, previousPayload, // Pass same payload as first attempt
|
|
1881
2595
|
this.createProgressCallback(agentResponseMessage, `${agentName} (retry)`), artifactInfo?.artifactId, artifactInfo?.versionId, configurationPresetId, // Pass same config as first attempt
|
|
1882
|
-
this.
|
|
2596
|
+
this.AppContext, // Embedder-supplied app/form context
|
|
1883
2597
|
this.PlanModeEnabled, // per-request Plan Mode toggle
|
|
1884
|
-
this._pendingRequestedSkillIDs)
|
|
2598
|
+
this._pendingRequestedSkillIDs, // user-requested skills (/skill mentions)
|
|
2599
|
+
this.AgentHistoryFrom);
|
|
1885
2600
|
if (retryResult && retryResult.success) {
|
|
1886
2601
|
// Retry succeeded - update the same message
|
|
1887
2602
|
if (retryResult.agentRun.AgentID) {
|
|
@@ -1890,7 +2605,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1890
2605
|
await this.updateConversationDetail(agentResponseMessage, retryResult.agentRun?.Message || `✅ **${agentName}** completed`, 'Complete', retryResult);
|
|
1891
2606
|
// Always emit artifactCreated to trigger UI reload (same as initial attempt)
|
|
1892
2607
|
this.emitArtifactReload(agentResponseMessage);
|
|
1893
|
-
this.
|
|
2608
|
+
this.MessageSent.emit(agentResponseMessage);
|
|
1894
2609
|
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
1895
2610
|
}
|
|
1896
2611
|
else {
|
|
@@ -1929,19 +2644,19 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1929
2644
|
* check if we should continue with the last agent for iterative refinement
|
|
1930
2645
|
*/
|
|
1931
2646
|
async handleSilentObservation(userMessage, conversationId) {
|
|
1932
|
-
// Find the last AI message (excluding Sage)
|
|
1933
|
-
const lastAIMessage = this.
|
|
1934
|
-
.slice()
|
|
1935
|
-
.reverse()
|
|
1936
|
-
.find(msg => msg.Role === 'AI' &&
|
|
1937
|
-
msg.AgentID &&
|
|
1938
|
-
!UUIDsEqual(msg.AgentID, this.converationManagerAgent?.ID));
|
|
2647
|
+
// Find the last AI message (excluding Sage) this turn may read
|
|
2648
|
+
const lastAIMessage = this.findLastNonSageReply();
|
|
1939
2649
|
if (!lastAIMessage || !lastAIMessage.AgentID) {
|
|
1940
2650
|
// No previous specialist agent - just mark user message as complete
|
|
1941
2651
|
console.log('🔇 No previous specialist agent found - marking complete');
|
|
1942
2652
|
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
1943
2653
|
return;
|
|
1944
2654
|
}
|
|
2655
|
+
if (!IsAgentAllowed(lastAIMessage.AgentID, this.AllowedAgentIDs)) {
|
|
2656
|
+
console.log('🔇 Previous specialist agent is not allowed in this chat - marking complete');
|
|
2657
|
+
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
2658
|
+
return;
|
|
2659
|
+
}
|
|
1945
2660
|
// Load the agent entity to get its name
|
|
1946
2661
|
const previousAgent = AIEngineBase.Instance.Agents.find(a => UUIDsEqual(a.ID, lastAIMessage.AgentID));
|
|
1947
2662
|
if (!previousAgent) {
|
|
@@ -1955,7 +2670,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1955
2670
|
// Resolved by QUERY, not from the window's artifact maps: `lastAIMessage` can sit inside
|
|
1956
2671
|
// the loaded window while its artifact does not, and this path silently degrades to a
|
|
1957
2672
|
// null payload when the lookup misses.
|
|
1958
|
-
const source = await this.agentService.FindLatestAgentOutputVersion(conversationId, lastAIMessage.AgentID);
|
|
2673
|
+
const source = await this.agentService.FindLatestAgentOutputVersion(conversationId, lastAIMessage.AgentID, this.AgentHistoryFrom);
|
|
1959
2674
|
if (source && source.payload != null) {
|
|
1960
2675
|
previousPayload = source.payload;
|
|
1961
2676
|
previousArtifactInfo = {
|
|
@@ -1966,16 +2681,16 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1966
2681
|
console.log('📦 Loaded previous OUTPUT artifact as payload for continuity', previousArtifactInfo);
|
|
1967
2682
|
}
|
|
1968
2683
|
// Create status message showing agent continuity
|
|
1969
|
-
const statusMessage = await this.dataCache.createConversationDetail(this.
|
|
2684
|
+
const statusMessage = await this.dataCache.createConversationDetail(this.CurrentUser);
|
|
1970
2685
|
statusMessage.ConversationID = conversationId;
|
|
1971
2686
|
statusMessage.Role = 'AI';
|
|
1972
2687
|
statusMessage.Message = `Continuing with **${agentName}** for refinement...`;
|
|
1973
2688
|
statusMessage.ParentID = userMessage.ID;
|
|
1974
2689
|
statusMessage.Status = 'Complete';
|
|
1975
2690
|
statusMessage.HiddenToUser = false;
|
|
1976
|
-
statusMessage.AgentID = this.
|
|
2691
|
+
statusMessage.AgentID = this.ConverationManagerAgent?.ID || null;
|
|
1977
2692
|
await statusMessage.Save();
|
|
1978
|
-
this.
|
|
2693
|
+
this.MessageSent.emit(statusMessage);
|
|
1979
2694
|
// Add agent to active tasks
|
|
1980
2695
|
const taskId = this.activeTasks.add({
|
|
1981
2696
|
agentName: agentName,
|
|
@@ -1983,19 +2698,20 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
1983
2698
|
relatedMessageId: userMessage.ID,
|
|
1984
2699
|
conversationDetailId: statusMessage.ID,
|
|
1985
2700
|
conversationId,
|
|
1986
|
-
conversationName: this.
|
|
2701
|
+
conversationName: this.ConversationName
|
|
1987
2702
|
});
|
|
1988
2703
|
try {
|
|
1989
2704
|
// Invoke the agent with the previous payload
|
|
1990
|
-
const continuityResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.
|
|
1991
|
-
this.
|
|
2705
|
+
const continuityResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.ConversationHistory, 'Continuing previous work based on user feedback', statusMessage.ID, previousPayload, this.createProgressCallback(statusMessage, agentName), previousArtifactInfo?.artifactId, previousArtifactInfo?.versionId, undefined, // configurationPresetId not used in this path
|
|
2706
|
+
this.AppContext, // Embedder-supplied app/form context
|
|
1992
2707
|
this.PlanModeEnabled, // per-request Plan Mode toggle
|
|
1993
|
-
this._pendingRequestedSkillIDs)
|
|
2708
|
+
this._pendingRequestedSkillIDs, // user-requested skills (/skill mentions)
|
|
2709
|
+
this.AgentHistoryFrom);
|
|
1994
2710
|
// Remove from active tasks
|
|
1995
2711
|
// Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
|
|
1996
2712
|
if (continuityResult && continuityResult.success) {
|
|
1997
2713
|
// Create response message
|
|
1998
|
-
const agentResponseMessage = await this.dataCache.createConversationDetail(this.
|
|
2714
|
+
const agentResponseMessage = await this.dataCache.createConversationDetail(this.CurrentUser);
|
|
1999
2715
|
agentResponseMessage.ConversationID = conversationId;
|
|
2000
2716
|
agentResponseMessage.Role = 'AI';
|
|
2001
2717
|
agentResponseMessage.Message = continuityResult.agentRun?.Message || `✅ **${agentName}** completed refinement`;
|
|
@@ -2004,12 +2720,12 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2004
2720
|
agentResponseMessage.HiddenToUser = false;
|
|
2005
2721
|
agentResponseMessage.AgentID = lastAIMessage.AgentID;
|
|
2006
2722
|
await agentResponseMessage.Save();
|
|
2007
|
-
this.
|
|
2723
|
+
this.MessageSent.emit(agentResponseMessage);
|
|
2008
2724
|
// Server created artifacts (handles versioning automatically) - emit event to trigger UI reload
|
|
2009
2725
|
if (continuityResult.payload && Object.keys(continuityResult.payload).length > 0) {
|
|
2010
2726
|
this.emitArtifactReload(agentResponseMessage);
|
|
2011
2727
|
console.log('🎨 Server created artifact (versioned) from agent continuity');
|
|
2012
|
-
this.
|
|
2728
|
+
this.MessageSent.emit(agentResponseMessage);
|
|
2013
2729
|
}
|
|
2014
2730
|
// Mark user message as complete
|
|
2015
2731
|
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
@@ -2037,7 +2753,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2037
2753
|
relatedMessageId: userMessage.ID,
|
|
2038
2754
|
conversationDetailId: userMessage.ID,
|
|
2039
2755
|
conversationId,
|
|
2040
|
-
conversationName: this.
|
|
2756
|
+
conversationName: this.ConversationName
|
|
2041
2757
|
});
|
|
2042
2758
|
// Declare agentResponseMessage outside try block so it's accessible in catch
|
|
2043
2759
|
let agentResponseMessage = undefined;
|
|
@@ -2046,11 +2762,11 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2046
2762
|
// (No UI uses User message 'In-Progress' - only AI messages need that status)
|
|
2047
2763
|
userMessage.Status = 'Complete';
|
|
2048
2764
|
await userMessage.Save();
|
|
2049
|
-
this.
|
|
2765
|
+
this.MessageSent.emit(userMessage);
|
|
2050
2766
|
// Look up the agent to get its ID
|
|
2051
2767
|
const agent = AIEngineBase.Instance.Agents.find(a => a.Name === agentName);
|
|
2052
2768
|
// Create AI response message BEFORE invoking agent (for duration tracking)
|
|
2053
|
-
agentResponseMessage = await this.dataCache.createConversationDetail(this.
|
|
2769
|
+
agentResponseMessage = await this.dataCache.createConversationDetail(this.CurrentUser);
|
|
2054
2770
|
agentResponseMessage.ConversationID = conversationId;
|
|
2055
2771
|
agentResponseMessage.Role = 'AI';
|
|
2056
2772
|
agentResponseMessage.Message = '⏳ Starting...'; // Initial message
|
|
@@ -2063,23 +2779,25 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2063
2779
|
}
|
|
2064
2780
|
// Save the record to establish __mj_CreatedAt timestamp
|
|
2065
2781
|
await agentResponseMessage.Save();
|
|
2066
|
-
this.
|
|
2782
|
+
this.MessageSent.emit(agentResponseMessage);
|
|
2067
2783
|
// Load previous payload if agent has been invoked before
|
|
2068
2784
|
const { payload: previousPayload, artifactInfo } = agent?.ID
|
|
2069
2785
|
? await this.loadPreviousPayloadForAgent(agent.ID)
|
|
2070
2786
|
: { payload: null, artifactInfo: null };
|
|
2071
2787
|
// Invoke the agent directly
|
|
2072
|
-
const result = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.
|
|
2788
|
+
const result = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.ConversationHistory, `User mentioned agent directly with @${agentName}`, agentResponseMessage.ID, previousPayload, // Pass previous payload for continuity
|
|
2073
2789
|
this.createProgressCallback(agentResponseMessage, agentName), artifactInfo?.artifactId, artifactInfo?.versionId, agentMention.configurationId, // Pass configuration preset ID
|
|
2074
|
-
this.
|
|
2790
|
+
this.AppContext, // Embedder-supplied app/form context
|
|
2075
2791
|
this.PlanModeEnabled, // per-request Plan Mode toggle
|
|
2076
|
-
this._pendingRequestedSkillIDs)
|
|
2792
|
+
this._pendingRequestedSkillIDs, // user-requested skills (/skill mentions)
|
|
2793
|
+
this.AgentHistoryFrom);
|
|
2077
2794
|
// Remove from active tasks
|
|
2078
2795
|
// Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
|
|
2079
2796
|
if (result && result.success) {
|
|
2080
2797
|
if (result.agentRun.AgentID) {
|
|
2081
2798
|
agentResponseMessage.AgentID = result.agentRun.AgentID;
|
|
2082
2799
|
}
|
|
2800
|
+
this.emitAfterAgentTurn(conversationId, result);
|
|
2083
2801
|
// Multi-stage response handling (same logic as ambient Sage)
|
|
2084
2802
|
// Stage 1: Check for task graph (multi-step orchestration)
|
|
2085
2803
|
if (result.payload?.taskGraph) {
|
|
@@ -2097,7 +2815,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2097
2815
|
// Server created artifacts - emit event to trigger UI reload
|
|
2098
2816
|
if (result.payload && Object.keys(result.payload).length > 0) {
|
|
2099
2817
|
this.emitArtifactReload(agentResponseMessage);
|
|
2100
|
-
this.
|
|
2818
|
+
this.MessageSent.emit(agentResponseMessage);
|
|
2101
2819
|
}
|
|
2102
2820
|
// Mark user message as complete
|
|
2103
2821
|
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
@@ -2127,6 +2845,11 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2127
2845
|
// Load the agent entity to get its name
|
|
2128
2846
|
const agent = AIEngineBase.Instance.Agents.find(a => UUIDsEqual(a.ID, agentId));
|
|
2129
2847
|
if (!agent) {
|
|
2848
|
+
if (!IsAgentAllowed(this.ConverationManagerAgent?.ID, this.AllowedAgentIDs)) {
|
|
2849
|
+
console.warn('⚠️ Could not load agent for continuation, and Sage is not allowed in this chat');
|
|
2850
|
+
await this.finishWithoutAgentTurn(userMessage, 'Declined');
|
|
2851
|
+
return;
|
|
2852
|
+
}
|
|
2130
2853
|
console.warn('⚠️ Could not load agent for continuation - falling back to Sage');
|
|
2131
2854
|
await this.processMessageThroughAgent(userMessage, { mentions: [], agentMention: null, userMentions: [], entityMentions: [], skillMentions: [] });
|
|
2132
2855
|
return;
|
|
@@ -2163,8 +2886,8 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2163
2886
|
// High) and applies to all subsequent non-mention routes. A
|
|
2164
2887
|
// history-derived preset still wins because it represents an
|
|
2165
2888
|
// explicit per-message intent the user expressed earlier.
|
|
2166
|
-
if (!previousConfigurationId && this.
|
|
2167
|
-
previousConfigurationId = this.
|
|
2889
|
+
if (!previousConfigurationId && this.AgentConfigurationPresetId) {
|
|
2890
|
+
previousConfigurationId = this.AgentConfigurationPresetId;
|
|
2168
2891
|
}
|
|
2169
2892
|
// Fall back to searching through all agent messages for an artifact
|
|
2170
2893
|
// This ensures payload continuity even after clarifying exchanges without artifacts
|
|
@@ -2173,7 +2896,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2173
2896
|
// used to walk is the loaded window, so the artifact it is looking for is exactly the
|
|
2174
2897
|
// one most likely to be missing from it.
|
|
2175
2898
|
if (!previousPayload) {
|
|
2176
|
-
const source = await this.agentService.FindLatestAgentOutputVersion(conversationId, agentId);
|
|
2899
|
+
const source = await this.agentService.FindLatestAgentOutputVersion(conversationId, agentId, this.AgentHistoryFrom);
|
|
2177
2900
|
if (source && source.payload != null) {
|
|
2178
2901
|
previousPayload = source.payload;
|
|
2179
2902
|
previousArtifactInfo = {
|
|
@@ -2210,7 +2933,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2210
2933
|
relatedMessageId: userMessage.ID,
|
|
2211
2934
|
conversationDetailId: userMessage.ID,
|
|
2212
2935
|
conversationId,
|
|
2213
|
-
conversationName: this.
|
|
2936
|
+
conversationName: this.ConversationName
|
|
2214
2937
|
});
|
|
2215
2938
|
// Declare agentResponseMessage outside try block so it's accessible in catch
|
|
2216
2939
|
let agentResponseMessage = undefined;
|
|
@@ -2219,9 +2942,9 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2219
2942
|
// (No UI uses User message 'In-Progress' - only AI messages need that status)
|
|
2220
2943
|
userMessage.Status = 'Complete';
|
|
2221
2944
|
await userMessage.Save();
|
|
2222
|
-
this.
|
|
2945
|
+
this.MessageSent.emit(userMessage);
|
|
2223
2946
|
// Create AI response message BEFORE invoking agent (for duration tracking)
|
|
2224
|
-
agentResponseMessage = await this.dataCache.createConversationDetail(this.
|
|
2947
|
+
agentResponseMessage = await this.dataCache.createConversationDetail(this.CurrentUser);
|
|
2225
2948
|
agentResponseMessage.ConversationID = conversationId;
|
|
2226
2949
|
agentResponseMessage.Role = 'AI';
|
|
2227
2950
|
agentResponseMessage.Message = '⏳ Starting...'; // Initial message
|
|
@@ -2231,26 +2954,28 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2231
2954
|
agentResponseMessage.AgentID = agentId;
|
|
2232
2955
|
// Save the record to establish __mj_CreatedAt timestamp
|
|
2233
2956
|
await agentResponseMessage.Save();
|
|
2234
|
-
this.
|
|
2957
|
+
this.MessageSent.emit(agentResponseMessage);
|
|
2235
2958
|
// Invoke the agent directly (continuation) with previous payload if available.
|
|
2236
2959
|
// `this.appContext` is forwarded so direct-routed sub-agents (e.g. Form
|
|
2237
2960
|
// Builder via [defaultAgentId]) see the embedder's ActiveForm/Schema/
|
|
2238
2961
|
// OverrideID block in their prompt — same flow Sage gets via
|
|
2239
2962
|
// `processMessage`.
|
|
2240
|
-
const result = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.
|
|
2963
|
+
const result = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.ConversationHistory, 'Continuing previous conversation with user', agentResponseMessage.ID, previousPayload, // Pass previous OUTPUT artifact payload for continuity
|
|
2241
2964
|
this.createProgressCallback(agentResponseMessage, agentName), previousArtifactInfo?.artifactId, previousArtifactInfo?.versionId, configurationId, // Pass configuration for continuity
|
|
2242
|
-
this.
|
|
2965
|
+
this.AppContext, // Embedder-supplied app/form context
|
|
2243
2966
|
this.PlanModeEnabled, // per-request Plan Mode toggle
|
|
2244
|
-
this._pendingRequestedSkillIDs)
|
|
2967
|
+
this._pendingRequestedSkillIDs, // user-requested skills (/skill mentions)
|
|
2968
|
+
this.AgentHistoryFrom);
|
|
2245
2969
|
// Remove from active tasks
|
|
2246
2970
|
// Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
|
|
2247
2971
|
if (result && result.success) {
|
|
2972
|
+
this.emitAfterAgentTurn(conversationId, result);
|
|
2248
2973
|
// Update the response message with agent result
|
|
2249
2974
|
await this.updateConversationDetail(agentResponseMessage, result.agentRun?.Message || `✅ **${agentName}** completed`, 'Complete', result);
|
|
2250
2975
|
// Server created artifacts (handles versioning) - emit event to trigger UI reload
|
|
2251
2976
|
if (result.payload && Object.keys(result.payload).length > 0) {
|
|
2252
2977
|
this.emitArtifactReload(agentResponseMessage);
|
|
2253
|
-
this.
|
|
2978
|
+
this.MessageSent.emit(agentResponseMessage);
|
|
2254
2979
|
}
|
|
2255
2980
|
// Mark user message as complete
|
|
2256
2981
|
await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
|
|
@@ -2284,11 +3009,11 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2284
3009
|
ConversationId: conversationId,
|
|
2285
3010
|
MessageText: plainTextMessage,
|
|
2286
3011
|
Provider: this.ProviderToUse,
|
|
2287
|
-
CurrentUser: this.
|
|
3012
|
+
CurrentUser: this.CurrentUser
|
|
2288
3013
|
});
|
|
2289
3014
|
if (result) {
|
|
2290
3015
|
// Emit event for animation in conversation list
|
|
2291
|
-
this.
|
|
3016
|
+
this.ConversationRenamed.emit({
|
|
2292
3017
|
conversationId,
|
|
2293
3018
|
name: result.Name,
|
|
2294
3019
|
description: result.Description
|
|
@@ -2352,7 +3077,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2352
3077
|
if (detail.Status === 'Complete' || detail.Status === 'Error') {
|
|
2353
3078
|
this.stopInFlightDetailWatch(detail.ID);
|
|
2354
3079
|
this.markMessageComplete(detail);
|
|
2355
|
-
this.
|
|
3080
|
+
this.MessageSent.emit(detail);
|
|
2356
3081
|
return;
|
|
2357
3082
|
}
|
|
2358
3083
|
}
|
|
@@ -2444,7 +3169,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2444
3169
|
LogStatusEx({ message: `[MarkComplete] No task registered against completed message ${conversationDetail.ID} — expected for any message that did not start the turn`, verboseOnly: true });
|
|
2445
3170
|
}
|
|
2446
3171
|
// Emit completion event to parent so it can refresh agent run data
|
|
2447
|
-
this.
|
|
3172
|
+
this.MessageComplete.emit({
|
|
2448
3173
|
conversationId: conversationDetail.ConversationID,
|
|
2449
3174
|
conversationDetailId: conversationDetail.ID,
|
|
2450
3175
|
agentId: conversationDetail.AgentID || undefined
|
|
@@ -2458,7 +3183,7 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2458
3183
|
* detail entity's immutable ConversationID, never this.conversationId.
|
|
2459
3184
|
*/
|
|
2460
3185
|
emitArtifactReload(detail) {
|
|
2461
|
-
this.
|
|
3186
|
+
this.ArtifactCreated.emit({
|
|
2462
3187
|
conversationId: detail.ConversationID,
|
|
2463
3188
|
artifactId: '',
|
|
2464
3189
|
versionId: '',
|
|
@@ -2481,8 +3206,8 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2481
3206
|
i0.ɵɵviewQuery(_c0, 5);
|
|
2482
3207
|
} if (rf & 2) {
|
|
2483
3208
|
let _t;
|
|
2484
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.
|
|
2485
|
-
} }, inputs: { conversationId: "conversationId", conversationName: "conversationName", currentUser: "currentUser", disabled: "disabled", placeholder: "placeholder", parentMessageId: "parentMessageId", enableAttachments: "enableAttachments", enableMentions: "enableMentions", enableAgentMentions: "enableAgentMentions", enableEntityMentions: "enableEntityMentions", enableSkillCommands: "enableSkillCommands", enablePlanMode: "enablePlanMode", enableRealtime: "enableRealtime", maxAttachments: "maxAttachments", maxAttachmentSizeBytes: "maxAttachmentSizeBytes", acceptedFileTypes: "acceptedFileTypes", artifactsByDetailId: "artifactsByDetailId", systemArtifactsByDetailId: "systemArtifactsByDetailId", agentRunsByDetailId: "agentRunsByDetailId", emptyStateMode: "emptyStateMode", appContext: "appContext", defaultAgentId: "defaultAgentId", conversationDefaultAgentId: "conversationDefaultAgentId", agentConfigurationPresetId: "agentConfigurationPresetId", initialMessage: "initialMessage", initialAttachments: "initialAttachments", conversationHistory: "conversationHistory", inProgressMessageIds: "inProgressMessageIds", applicationId: "applicationId", initialDraft: "initialDraft" }, outputs: { messageSent: "messageSent", agentResponse: "agentResponse", beforeAgentTurn: "beforeAgentTurn", afterAgentTurn: "afterAgentTurn", agentRunDetected: "agentRunDetected", agentRunUpdate: "agentRunUpdate", messageComplete: "messageComplete", artifactCreated: "artifactCreated", conversationRenamed: "conversationRenamed", intentCheckStarted: "intentCheckStarted", intentCheckCompleted: "intentCheckCompleted", initialMessageAutoSendStarted: "initialMessageAutoSendStarted", initialMessageAutoSendFailed: "initialMessageAutoSendFailed", emptyStateSubmit: "emptyStateSubmit", uploadStateChanged: "uploadStateChanged", initialDraftApplied: "initialDraftApplied", DraftStateChanged: "DraftStateChanged", ComposerBlurred: "ComposerBlurred" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 6, vars:
|
|
3209
|
+
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.InputBox = _t.first);
|
|
3210
|
+
} }, inputs: { ConversationId: "ConversationId", conversationId: "conversationId", ConversationName: "ConversationName", conversationName: "conversationName", CurrentUser: "CurrentUser", currentUser: "currentUser", Disabled: "Disabled", disabled: "disabled", Placeholder: "Placeholder", placeholder: "placeholder", ParentMessageId: "ParentMessageId", parentMessageId: "parentMessageId", EnableAttachments: "EnableAttachments", enableAttachments: "enableAttachments", EnableMentions: "EnableMentions", enableMentions: "enableMentions", EnableAgentMentions: "EnableAgentMentions", enableAgentMentions: "enableAgentMentions", EnableEntityMentions: "EnableEntityMentions", enableEntityMentions: "enableEntityMentions", EnableSkillCommands: "EnableSkillCommands", enableSkillCommands: "enableSkillCommands", EnablePlanMode: "EnablePlanMode", enablePlanMode: "enablePlanMode", EnableRealtime: "EnableRealtime", enableRealtime: "enableRealtime", MaxAttachments: "MaxAttachments", maxAttachments: "maxAttachments", MaxAttachmentSizeBytes: "MaxAttachmentSizeBytes", maxAttachmentSizeBytes: "maxAttachmentSizeBytes", AcceptedFileTypes: "AcceptedFileTypes", acceptedFileTypes: "acceptedFileTypes", ArtifactsByDetailId: "ArtifactsByDetailId", artifactsByDetailId: "artifactsByDetailId", SystemArtifactsByDetailId: "SystemArtifactsByDetailId", systemArtifactsByDetailId: "systemArtifactsByDetailId", AgentRunsByDetailId: "AgentRunsByDetailId", agentRunsByDetailId: "agentRunsByDetailId", EmptyStateMode: "EmptyStateMode", emptyStateMode: "emptyStateMode", AppContext: "AppContext", appContext: "appContext", DefaultAgentId: "DefaultAgentId", defaultAgentId: "defaultAgentId", ConversationDefaultAgentId: "ConversationDefaultAgentId", conversationDefaultAgentId: "conversationDefaultAgentId", AgentConfigurationPresetId: "AgentConfigurationPresetId", agentConfigurationPresetId: "agentConfigurationPresetId", InitialMessage: "InitialMessage", initialMessage: "initialMessage", InitialAttachments: "InitialAttachments", initialAttachments: "initialAttachments", ConversationHistory: "ConversationHistory", conversationHistory: "conversationHistory", InProgressMessageIds: "InProgressMessageIds", inProgressMessageIds: "inProgressMessageIds", ApplicationId: "ApplicationId", applicationId: "applicationId", AgentReplyMode: "AgentReplyMode", AllowedAgentIDs: "AllowedAgentIDs", MentionPeople: "MentionPeople", AgentHistoryFrom: "AgentHistoryFrom", AgentTurnHandler: "AgentTurnHandler", AutoNameConversation: "AutoNameConversation", InitialDraft: "InitialDraft", initialDraft: "initialDraft" }, outputs: { MessageSent: "MessageSent", messageSent: "messageSent", AgentResponse: "AgentResponse", agentResponse: "agentResponse", BeforeAgentTurn: "BeforeAgentTurn", beforeAgentTurn: "beforeAgentTurn", AfterAgentTurn: "AfterAgentTurn", afterAgentTurn: "afterAgentTurn", AgentRunDetected: "AgentRunDetected", agentRunDetected: "agentRunDetected", AgentRunUpdate: "AgentRunUpdate", agentRunUpdate: "agentRunUpdate", MessageComplete: "MessageComplete", messageComplete: "messageComplete", ArtifactCreated: "ArtifactCreated", artifactCreated: "artifactCreated", ConversationRenamed: "ConversationRenamed", conversationRenamed: "conversationRenamed", IntentCheckStarted: "IntentCheckStarted", intentCheckStarted: "intentCheckStarted", IntentCheckCompleted: "IntentCheckCompleted", intentCheckCompleted: "intentCheckCompleted", InitialMessageAutoSendStarted: "InitialMessageAutoSendStarted", initialMessageAutoSendStarted: "initialMessageAutoSendStarted", InitialMessageAutoSendFailed: "InitialMessageAutoSendFailed", initialMessageAutoSendFailed: "initialMessageAutoSendFailed", EmptyStateSubmit: "EmptyStateSubmit", emptyStateSubmit: "emptyStateSubmit", UploadStateChanged: "UploadStateChanged", uploadStateChanged: "uploadStateChanged", InitialDraftApplied: "InitialDraftApplied", initialDraftApplied: "initialDraftApplied", DraftStateChanged: "DraftStateChanged", ComposerBlurred: "ComposerBlurred" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 6, vars: 29, consts: [["pickerOrigin", "cdkOverlayOrigin"], ["inputBox", ""], ["cdkOverlayOrigin", "", 1, "message-input-wrapper"], [1, "processing-indicator"], [3, "valueChange", "blurred", "textSubmitted", "attachmentsChanged", "attachmentError", "voiceRequested", "voiceOptionsRequested", "planModeToggle", "placeholder", "disabled", "showCharacterCount", "enableMentions", "EnableAgentMentions", "EnableEntityMentions", "EnableSkillCommands", "TargetAgentId", "AllowedAgentIDs", "MentionPeople", "enableAttachments", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes", "currentUser", "Provider", "rows", "enableRealtime", "voiceActive", "canStartRealtime", "enablePlanMode", "planModeActive", "value"], ["cdkConnectedOverlay", "", "cdkConnectedOverlayBackdropClass", "cdk-overlay-transparent-backdrop", 3, "backdropClick", "detach", "cdkConnectedOverlayOrigin", "cdkConnectedOverlayOpen", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPush", "cdkConnectedOverlayHasBackdrop"], [1, "fas", "fa-circle-notch", "fa-spin"], [3, "AgentPicked", "Cancelled", "Provider", "CurrentUser", "Agents", "DefaultAgentId", "CoAgents", "DefaultCoAgentId"]], template: function MessageInputComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2486
3211
|
i0.ɵɵelementStart(0, "div", 2, 0);
|
|
2487
3212
|
i0.ɵɵconditionalCreate(2, MessageInputComponent_Conditional_2_Template, 4, 1, "div", 3);
|
|
2488
3213
|
i0.ɵɵelementStart(3, "mj-ai-composer", 4, 1);
|
|
@@ -2496,107 +3221,211 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2496
3221
|
i0.ɵɵadvance(2);
|
|
2497
3222
|
i0.ɵɵconditional(ctx.isProcessing ? 2 : -1);
|
|
2498
3223
|
i0.ɵɵadvance();
|
|
2499
|
-
i0.ɵɵproperty("placeholder", ctx.placeholder)("disabled", ctx.disabled || ctx.isProcessing)("showCharacterCount", false)("enableMentions", ctx.enableMentions)("EnableAgentMentions", ctx.enableAgentMentions)("EnableEntityMentions", ctx.enableEntityMentions)("EnableSkillCommands", ctx.enableSkillCommands)("TargetAgentId", ctx.pickerTargetAgentId)("enableAttachments", ctx.enableAttachments)("maxAttachments", ctx.maxAttachments)("maxAttachmentSizeBytes", ctx.maxAttachmentSizeBytes)("acceptedFileTypes", ctx.acceptedFileTypes)("currentUser", ctx.currentUser)("Provider", ctx.Provider)("rows", 3)("enableRealtime", ctx.enableRealtime)("voiceActive", ctx.voiceActive)("canStartRealtime", ctx.canStartRealtime)("enablePlanMode", ctx.enablePlanMode)("planModeActive", ctx.PlanModeEnabled)("value", ctx.messageText);
|
|
3224
|
+
i0.ɵɵproperty("placeholder", ctx.placeholder)("disabled", ctx.disabled || ctx.isProcessing)("showCharacterCount", false)("enableMentions", ctx.enableMentions)("EnableAgentMentions", ctx.enableAgentMentions)("EnableEntityMentions", ctx.enableEntityMentions)("EnableSkillCommands", ctx.enableSkillCommands)("TargetAgentId", ctx.pickerTargetAgentId)("AllowedAgentIDs", ctx.AllowedAgentIDs)("MentionPeople", ctx.MentionPeople)("enableAttachments", ctx.enableAttachments)("maxAttachments", ctx.maxAttachments)("maxAttachmentSizeBytes", ctx.maxAttachmentSizeBytes)("acceptedFileTypes", ctx.acceptedFileTypes)("currentUser", ctx.currentUser)("Provider", ctx.Provider)("rows", 3)("enableRealtime", ctx.enableRealtime)("voiceActive", ctx.voiceActive)("canStartRealtime", ctx.canStartRealtime)("enablePlanMode", ctx.enablePlanMode)("planModeActive", ctx.PlanModeEnabled)("value", ctx.messageText);
|
|
2500
3225
|
i0.ɵɵadvance(2);
|
|
2501
3226
|
i0.ɵɵproperty("cdkConnectedOverlayOrigin", pickerOrigin_r3)("cdkConnectedOverlayOpen", ctx.showRealtimeAgentPicker)("cdkConnectedOverlayPositions", ctx.pickerOverlayPositions)("cdkConnectedOverlayPush", true)("cdkConnectedOverlayHasBackdrop", true);
|
|
2502
3227
|
} }, dependencies: [i11.CdkConnectedOverlay, i11.CdkOverlayOrigin, i12.RealtimeAgentPickerComponent, i13.AiComposerComponent], styles: [".message-input-wrapper[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n}\n\n\n\n\n.processing-indicator[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 95%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n pointer-events: none;\n}\n.processing-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n.processing-indicator[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 0.9rem;\n color: var(--mj-text-primary);\n}"] });
|
|
2503
3228
|
}
|
|
2504
3229
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MessageInputComponent, [{
|
|
2505
3230
|
type: Component,
|
|
2506
|
-
args: [{ standalone: false, selector: 'mj-message-input', template: "<div class=\"message-input-wrapper\" cdkOverlayOrigin #pickerOrigin=\"cdkOverlayOrigin\">\n <!-- Processing Indicator Overlay -->\n @if (isProcessing) {\n <div class=\"processing-indicator\">\n <i class=\"fas fa-circle-notch fa-spin\"></i>\n <span>{{ processingMessage }}</span>\n </div>\n }\n\n <!-- AI composer (mic + Plan Mode buttons live in its in-composer toolbar): wraps the\n generic mj-message-input-box with the '@' agent / '#' record / '/' skill trigger\n plugins built in \u2014 all three on by default, preserving the standard chat behavior. -->\n <mj-ai-composer\n #inputBox\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled || isProcessing\"\n [showCharacterCount]=\"false\"\n [enableMentions]=\"enableMentions\"\n [EnableAgentMentions]=\"enableAgentMentions\"\n [EnableEntityMentions]=\"enableEntityMentions\"\n [EnableSkillCommands]=\"enableSkillCommands\"\n [TargetAgentId]=\"pickerTargetAgentId\"\n [enableAttachments]=\"enableAttachments\"\n [maxAttachments]=\"maxAttachments\"\n [maxAttachmentSizeBytes]=\"maxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"acceptedFileTypes\"\n [currentUser]=\"currentUser\"\n [Provider]=\"Provider\"\n [rows]=\"3\"\n [enableRealtime]=\"enableRealtime\"\n [voiceActive]=\"voiceActive\"\n [canStartRealtime]=\"canStartRealtime\"\n [enablePlanMode]=\"enablePlanMode\"\n [planModeActive]=\"PlanModeEnabled\"\n [value]=\"messageText\"\n (valueChange)=\"OnComposerValueChanged($event)\"\n (blurred)=\"ComposerBlurred.emit()\"\n (textSubmitted)=\"onTextSubmitted($event)\"\n (attachmentsChanged)=\"onAttachmentsChanged($event)\"\n (attachmentError)=\"onAttachmentError($event)\"\n (voiceRequested)=\"onStartRealtime()\"\n (voiceOptionsRequested)=\"onRealtimeOptions()\"\n (planModeToggle)=\"TogglePlanMode()\">\n </mj-ai-composer>\n\n <!-- Voice agent/co-agent/model picker \u2014 shown when starting a call on a conversation\n with NO prior agent participation, or on demand via the caret next to the phone\n button (any conversation). Rendered in a body-level CDK overlay anchored above the\n composer so it POPS OUT of the chat overlay's clipping border instead of being cut\n off at the top of a narrow (~390px) overlay. -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"pickerOrigin\"\n [cdkConnectedOverlayOpen]=\"showRealtimeAgentPicker\"\n [cdkConnectedOverlayPositions]=\"pickerOverlayPositions\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"onRealtimeAgentPickerCancelled()\"\n (detach)=\"onRealtimeAgentPickerCancelled()\">\n <mj-realtime-agent-picker\n [Provider]=\"ProviderToUse\"\n [CurrentUser]=\"currentUser\"\n [Agents]=\"voicePickerAgents\"\n [DefaultAgentId]=\"voicePickerDefaultAgentId\"\n [CoAgents]=\"voicePickerCoAgents\"\n [DefaultCoAgentId]=\"voicePickerDefaultCoAgentId\"\n (AgentPicked)=\"onRealtimeAgentPicked($event)\"\n (Cancelled)=\"onRealtimeAgentPickerCancelled()\">\n </mj-realtime-agent-picker>\n </ng-template>\n</div>\n\n<!-- The voice \"call mode\" overlay is hosted by <mj-conversation-chat-area> (it fills the\n whole conversation panel in place); this component only owns the trigger wiring. -->\n", styles: [".message-input-wrapper {\n position: relative;\n width: 100%;\n}\n\n/* Plan Mode moved into the in-composer toolbar (message-input-box) as a toggle icon button\n next to the attachment/voice buttons \u2014 see .plan-mode-button-icon there. */\n\n.processing-indicator {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 95%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n pointer-events: none;\n}\n.processing-indicator i {\n color: var(--mj-brand-primary);\n}\n.processing-indicator span {\n font-size: 0.9rem;\n color: var(--mj-text-primary);\n}\n"] }]
|
|
2507
|
-
}], () => [{ type: i1.DialogService }, { type: i2.ToastService }, { type: i3.ConversationAgentService }, { type: i4.DataCacheService }, { type: i5.ActiveTasksService }, { type: i6.ConversationStreamingService }, { type: i7.MentionParserService }, { type: i8.ConversationAttachmentService }, { type: i9.ConversationBridgeService }, { type: i10.RealtimeSessionService }], {
|
|
3231
|
+
args: [{ standalone: false, selector: 'mj-message-input', template: "<div class=\"message-input-wrapper\" cdkOverlayOrigin #pickerOrigin=\"cdkOverlayOrigin\">\n <!-- Processing Indicator Overlay -->\n @if (isProcessing) {\n <div class=\"processing-indicator\">\n <i class=\"fas fa-circle-notch fa-spin\"></i>\n <span>{{ processingMessage }}</span>\n </div>\n }\n\n <!-- AI composer (mic + Plan Mode buttons live in its in-composer toolbar): wraps the\n generic mj-message-input-box with the '@' agent / '#' record / '/' skill trigger\n plugins built in \u2014 all three on by default, preserving the standard chat behavior. -->\n <mj-ai-composer\n #inputBox\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled || isProcessing\"\n [showCharacterCount]=\"false\"\n [enableMentions]=\"enableMentions\"\n [EnableAgentMentions]=\"enableAgentMentions\"\n [EnableEntityMentions]=\"enableEntityMentions\"\n [EnableSkillCommands]=\"enableSkillCommands\"\n [TargetAgentId]=\"pickerTargetAgentId\"\n [AllowedAgentIDs]=\"AllowedAgentIDs\"\n [MentionPeople]=\"MentionPeople\"\n [enableAttachments]=\"enableAttachments\"\n [maxAttachments]=\"maxAttachments\"\n [maxAttachmentSizeBytes]=\"maxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"acceptedFileTypes\"\n [currentUser]=\"currentUser\"\n [Provider]=\"Provider\"\n [rows]=\"3\"\n [enableRealtime]=\"enableRealtime\"\n [voiceActive]=\"voiceActive\"\n [canStartRealtime]=\"canStartRealtime\"\n [enablePlanMode]=\"enablePlanMode\"\n [planModeActive]=\"PlanModeEnabled\"\n [value]=\"messageText\"\n (valueChange)=\"OnComposerValueChanged($event)\"\n (blurred)=\"ComposerBlurred.emit()\"\n (textSubmitted)=\"onTextSubmitted($event)\"\n (attachmentsChanged)=\"onAttachmentsChanged($event)\"\n (attachmentError)=\"onAttachmentError($event)\"\n (voiceRequested)=\"onStartRealtime()\"\n (voiceOptionsRequested)=\"onRealtimeOptions()\"\n (planModeToggle)=\"TogglePlanMode()\">\n </mj-ai-composer>\n\n <!-- Voice agent/co-agent/model picker \u2014 shown when starting a call on a conversation\n with NO prior agent participation, or on demand via the caret next to the phone\n button (any conversation). Rendered in a body-level CDK overlay anchored above the\n composer so it POPS OUT of the chat overlay's clipping border instead of being cut\n off at the top of a narrow (~390px) overlay. -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"pickerOrigin\"\n [cdkConnectedOverlayOpen]=\"showRealtimeAgentPicker\"\n [cdkConnectedOverlayPositions]=\"pickerOverlayPositions\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (backdropClick)=\"onRealtimeAgentPickerCancelled()\"\n (detach)=\"onRealtimeAgentPickerCancelled()\">\n <mj-realtime-agent-picker\n [Provider]=\"ProviderToUse\"\n [CurrentUser]=\"currentUser\"\n [Agents]=\"voicePickerAgents\"\n [DefaultAgentId]=\"voicePickerDefaultAgentId\"\n [CoAgents]=\"voicePickerCoAgents\"\n [DefaultCoAgentId]=\"voicePickerDefaultCoAgentId\"\n (AgentPicked)=\"onRealtimeAgentPicked($event)\"\n (Cancelled)=\"onRealtimeAgentPickerCancelled()\">\n </mj-realtime-agent-picker>\n </ng-template>\n</div>\n\n<!-- The voice \"call mode\" overlay is hosted by <mj-conversation-chat-area> (it fills the\n whole conversation panel in place); this component only owns the trigger wiring. -->\n", styles: [".message-input-wrapper {\n position: relative;\n width: 100%;\n}\n\n/* Plan Mode moved into the in-composer toolbar (message-input-box) as a toggle icon button\n next to the attachment/voice buttons \u2014 see .plan-mode-button-icon there. */\n\n.processing-indicator {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n background: color-mix(in srgb, var(--mj-bg-surface-card) 95%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n pointer-events: none;\n}\n.processing-indicator i {\n color: var(--mj-brand-primary);\n}\n.processing-indicator span {\n font-size: 0.9rem;\n color: var(--mj-text-primary);\n}\n"] }]
|
|
3232
|
+
}], () => [{ type: i1.DialogService }, { type: i2.ToastService }, { type: i3.ConversationAgentService }, { type: i4.DataCacheService }, { type: i5.ActiveTasksService }, { type: i6.ConversationStreamingService }, { type: i7.MentionParserService }, { type: i8.ConversationAttachmentService }, { type: i9.ConversationBridgeService }, { type: i10.RealtimeSessionService }], { ConversationId: [{
|
|
3233
|
+
type: Input
|
|
3234
|
+
}], conversationId: [{
|
|
3235
|
+
type: Input
|
|
3236
|
+
}], ConversationName: [{
|
|
2508
3237
|
type: Input
|
|
2509
3238
|
}], conversationName: [{
|
|
2510
3239
|
type: Input
|
|
3240
|
+
}], CurrentUser: [{
|
|
3241
|
+
type: Input
|
|
2511
3242
|
}], currentUser: [{
|
|
2512
3243
|
type: Input
|
|
3244
|
+
}], Disabled: [{
|
|
3245
|
+
type: Input
|
|
2513
3246
|
}], disabled: [{
|
|
2514
3247
|
type: Input
|
|
3248
|
+
}], Placeholder: [{
|
|
3249
|
+
type: Input
|
|
2515
3250
|
}], placeholder: [{
|
|
2516
3251
|
type: Input
|
|
3252
|
+
}], ParentMessageId: [{
|
|
3253
|
+
type: Input
|
|
2517
3254
|
}], parentMessageId: [{
|
|
2518
3255
|
type: Input
|
|
3256
|
+
}], EnableAttachments: [{
|
|
3257
|
+
type: Input
|
|
2519
3258
|
}], enableAttachments: [{
|
|
2520
3259
|
type: Input
|
|
3260
|
+
}], EnableMentions: [{
|
|
3261
|
+
type: Input
|
|
2521
3262
|
}], enableMentions: [{
|
|
2522
3263
|
type: Input
|
|
3264
|
+
}], EnableAgentMentions: [{
|
|
3265
|
+
type: Input
|
|
2523
3266
|
}], enableAgentMentions: [{
|
|
2524
3267
|
type: Input
|
|
3268
|
+
}], EnableEntityMentions: [{
|
|
3269
|
+
type: Input
|
|
2525
3270
|
}], enableEntityMentions: [{
|
|
2526
3271
|
type: Input
|
|
3272
|
+
}], EnableSkillCommands: [{
|
|
3273
|
+
type: Input
|
|
2527
3274
|
}], enableSkillCommands: [{
|
|
2528
3275
|
type: Input
|
|
3276
|
+
}], EnablePlanMode: [{
|
|
3277
|
+
type: Input
|
|
2529
3278
|
}], enablePlanMode: [{
|
|
2530
3279
|
type: Input
|
|
3280
|
+
}], EnableRealtime: [{
|
|
3281
|
+
type: Input
|
|
2531
3282
|
}], enableRealtime: [{
|
|
2532
3283
|
type: Input
|
|
3284
|
+
}], MaxAttachments: [{
|
|
3285
|
+
type: Input
|
|
2533
3286
|
}], maxAttachments: [{
|
|
2534
3287
|
type: Input
|
|
3288
|
+
}], MaxAttachmentSizeBytes: [{
|
|
3289
|
+
type: Input
|
|
2535
3290
|
}], maxAttachmentSizeBytes: [{
|
|
2536
3291
|
type: Input
|
|
3292
|
+
}], AcceptedFileTypes: [{
|
|
3293
|
+
type: Input
|
|
2537
3294
|
}], acceptedFileTypes: [{
|
|
2538
3295
|
type: Input
|
|
3296
|
+
}], ArtifactsByDetailId: [{
|
|
3297
|
+
type: Input
|
|
2539
3298
|
}], artifactsByDetailId: [{
|
|
2540
3299
|
type: Input
|
|
3300
|
+
}], SystemArtifactsByDetailId: [{
|
|
3301
|
+
type: Input
|
|
2541
3302
|
}], systemArtifactsByDetailId: [{
|
|
2542
3303
|
type: Input
|
|
3304
|
+
}], AgentRunsByDetailId: [{
|
|
3305
|
+
type: Input
|
|
2543
3306
|
}], agentRunsByDetailId: [{
|
|
2544
3307
|
type: Input
|
|
3308
|
+
}], EmptyStateMode: [{
|
|
3309
|
+
type: Input
|
|
2545
3310
|
}], emptyStateMode: [{
|
|
2546
3311
|
type: Input
|
|
3312
|
+
}], AppContext: [{
|
|
3313
|
+
type: Input
|
|
2547
3314
|
}], appContext: [{
|
|
2548
3315
|
type: Input
|
|
3316
|
+
}], DefaultAgentId: [{
|
|
3317
|
+
type: Input
|
|
2549
3318
|
}], defaultAgentId: [{
|
|
2550
3319
|
type: Input
|
|
3320
|
+
}], ConversationDefaultAgentId: [{
|
|
3321
|
+
type: Input
|
|
2551
3322
|
}], conversationDefaultAgentId: [{
|
|
2552
3323
|
type: Input
|
|
3324
|
+
}], AgentConfigurationPresetId: [{
|
|
3325
|
+
type: Input
|
|
2553
3326
|
}], agentConfigurationPresetId: [{
|
|
2554
3327
|
type: Input
|
|
3328
|
+
}], InitialMessage: [{
|
|
3329
|
+
type: Input
|
|
2555
3330
|
}], initialMessage: [{
|
|
2556
3331
|
type: Input
|
|
3332
|
+
}], InitialAttachments: [{
|
|
3333
|
+
type: Input
|
|
2557
3334
|
}], initialAttachments: [{
|
|
2558
3335
|
type: Input
|
|
3336
|
+
}], ConversationHistory: [{
|
|
3337
|
+
type: Input
|
|
2559
3338
|
}], conversationHistory: [{
|
|
2560
3339
|
type: Input
|
|
3340
|
+
}], InProgressMessageIds: [{
|
|
3341
|
+
type: Input
|
|
2561
3342
|
}], inProgressMessageIds: [{
|
|
2562
3343
|
type: Input
|
|
3344
|
+
}], ApplicationId: [{
|
|
3345
|
+
type: Input
|
|
2563
3346
|
}], applicationId: [{
|
|
2564
3347
|
type: Input
|
|
3348
|
+
}], AgentReplyMode: [{
|
|
3349
|
+
type: Input
|
|
3350
|
+
}], AllowedAgentIDs: [{
|
|
3351
|
+
type: Input
|
|
3352
|
+
}], MentionPeople: [{
|
|
3353
|
+
type: Input
|
|
3354
|
+
}], AgentHistoryFrom: [{
|
|
3355
|
+
type: Input
|
|
3356
|
+
}], AgentTurnHandler: [{
|
|
3357
|
+
type: Input
|
|
3358
|
+
}], AutoNameConversation: [{
|
|
3359
|
+
type: Input
|
|
3360
|
+
}], MessageSent: [{
|
|
3361
|
+
type: Output
|
|
2565
3362
|
}], messageSent: [{
|
|
2566
3363
|
type: Output
|
|
3364
|
+
}], AgentResponse: [{
|
|
3365
|
+
type: Output
|
|
2567
3366
|
}], agentResponse: [{
|
|
2568
3367
|
type: Output
|
|
3368
|
+
}], BeforeAgentTurn: [{
|
|
3369
|
+
type: Output
|
|
2569
3370
|
}], beforeAgentTurn: [{
|
|
2570
3371
|
type: Output
|
|
3372
|
+
}], AfterAgentTurn: [{
|
|
3373
|
+
type: Output
|
|
2571
3374
|
}], afterAgentTurn: [{
|
|
2572
3375
|
type: Output
|
|
3376
|
+
}], AgentRunDetected: [{
|
|
3377
|
+
type: Output
|
|
2573
3378
|
}], agentRunDetected: [{
|
|
2574
3379
|
type: Output
|
|
3380
|
+
}], AgentRunUpdate: [{
|
|
3381
|
+
type: Output
|
|
2575
3382
|
}], agentRunUpdate: [{
|
|
2576
3383
|
type: Output
|
|
3384
|
+
}], MessageComplete: [{
|
|
3385
|
+
type: Output
|
|
2577
3386
|
}], messageComplete: [{
|
|
2578
3387
|
type: Output
|
|
3388
|
+
}], ArtifactCreated: [{
|
|
3389
|
+
type: Output
|
|
2579
3390
|
}], artifactCreated: [{
|
|
2580
3391
|
type: Output
|
|
3392
|
+
}], ConversationRenamed: [{
|
|
3393
|
+
type: Output
|
|
2581
3394
|
}], conversationRenamed: [{
|
|
2582
3395
|
type: Output
|
|
3396
|
+
}], IntentCheckStarted: [{
|
|
3397
|
+
type: Output
|
|
2583
3398
|
}], intentCheckStarted: [{
|
|
2584
3399
|
type: Output
|
|
3400
|
+
}], IntentCheckCompleted: [{
|
|
3401
|
+
type: Output
|
|
2585
3402
|
}], intentCheckCompleted: [{
|
|
2586
3403
|
type: Output
|
|
3404
|
+
}], InitialMessageAutoSendStarted: [{
|
|
3405
|
+
type: Output
|
|
2587
3406
|
}], initialMessageAutoSendStarted: [{
|
|
2588
3407
|
type: Output
|
|
3408
|
+
}], InitialMessageAutoSendFailed: [{
|
|
3409
|
+
type: Output
|
|
2589
3410
|
}], initialMessageAutoSendFailed: [{
|
|
2590
3411
|
type: Output
|
|
3412
|
+
}], EmptyStateSubmit: [{
|
|
3413
|
+
type: Output
|
|
2591
3414
|
}], emptyStateSubmit: [{
|
|
2592
3415
|
type: Output
|
|
3416
|
+
}], UploadStateChanged: [{
|
|
3417
|
+
type: Output
|
|
2593
3418
|
}], uploadStateChanged: [{
|
|
2594
3419
|
type: Output
|
|
2595
|
-
}],
|
|
3420
|
+
}], InputBox: [{
|
|
2596
3421
|
type: ViewChild,
|
|
2597
3422
|
args: ['inputBox']
|
|
3423
|
+
}], InitialDraft: [{
|
|
3424
|
+
type: Input
|
|
2598
3425
|
}], initialDraft: [{
|
|
2599
3426
|
type: Input
|
|
3427
|
+
}], InitialDraftApplied: [{
|
|
3428
|
+
type: Output
|
|
2600
3429
|
}], initialDraftApplied: [{
|
|
2601
3430
|
type: Output
|
|
2602
3431
|
}], DraftStateChanged: [{
|
|
@@ -2604,5 +3433,5 @@ export class MessageInputComponent extends BaseAngularComponent {
|
|
|
2604
3433
|
}], ComposerBlurred: [{
|
|
2605
3434
|
type: Output
|
|
2606
3435
|
}] }); })();
|
|
2607
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MessageInputComponent, { className: "MessageInputComponent", filePath: "src/lib/components/message/message-input.component.ts", lineNumber:
|
|
3436
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MessageInputComponent, { className: "MessageInputComponent", filePath: "src/lib/components/message/message-input.component.ts", lineNumber: 48 }); })();
|
|
2608
3437
|
//# sourceMappingURL=message-input.component.js.map
|