@memberjunction/ng-conversations 2.104.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +197 -0
- package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts +20 -0
- package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts.map +1 -0
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js +125 -0
- package/dist/lib/components/active-tasks/active-tasks-panel.component.js.map +1 -0
- package/dist/lib/components/agent/active-agent-indicator.component.d.ts +48 -0
- package/dist/lib/components/agent/active-agent-indicator.component.d.ts.map +1 -0
- package/dist/lib/components/agent/active-agent-indicator.component.js +199 -0
- package/dist/lib/components/agent/active-agent-indicator.component.js.map +1 -0
- package/dist/lib/components/agent/agent-process-panel.component.d.ts +30 -0
- package/dist/lib/components/agent/agent-process-panel.component.d.ts.map +1 -0
- package/dist/lib/components/agent/agent-process-panel.component.js +333 -0
- package/dist/lib/components/agent/agent-process-panel.component.js.map +1 -0
- package/dist/lib/components/artifact/artifact-panel.component.d.ts +22 -0
- package/dist/lib/components/artifact/artifact-panel.component.d.ts.map +1 -0
- package/dist/lib/components/artifact/artifact-panel.component.js +237 -0
- package/dist/lib/components/artifact/artifact-panel.component.js.map +1 -0
- package/dist/lib/components/artifact/artifact-upload-modal.component.d.ts +39 -0
- package/dist/lib/components/artifact/artifact-upload-modal.component.d.ts.map +1 -0
- package/dist/lib/components/artifact/artifact-upload-modal.component.js +384 -0
- package/dist/lib/components/artifact/artifact-upload-modal.component.js.map +1 -0
- package/dist/lib/components/artifact/artifact-version-history.component.d.ts +28 -0
- package/dist/lib/components/artifact/artifact-version-history.component.d.ts.map +1 -0
- package/dist/lib/components/artifact/artifact-version-history.component.js +280 -0
- package/dist/lib/components/artifact/artifact-version-history.component.js.map +1 -0
- package/dist/lib/components/artifact/artifact-viewer-panel.component.d.ts +22 -0
- package/dist/lib/components/artifact/artifact-viewer-panel.component.d.ts.map +1 -0
- package/dist/lib/components/artifact/artifact-viewer-panel.component.js +182 -0
- package/dist/lib/components/artifact/artifact-viewer-panel.component.js.map +1 -0
- package/dist/lib/components/artifact/artifact-viewer.component.d.ts +27 -0
- package/dist/lib/components/artifact/artifact-viewer.component.d.ts.map +1 -0
- package/dist/lib/components/artifact/artifact-viewer.component.js +266 -0
- package/dist/lib/components/artifact/artifact-viewer.component.js.map +1 -0
- package/dist/lib/components/artifact/inline-artifact.component.d.ts +46 -0
- package/dist/lib/components/artifact/inline-artifact.component.d.ts.map +1 -0
- package/dist/lib/components/artifact/inline-artifact.component.js +447 -0
- package/dist/lib/components/artifact/inline-artifact.component.js.map +1 -0
- package/dist/lib/components/collection/collection-artifact-card.component.d.ts +18 -0
- package/dist/lib/components/collection/collection-artifact-card.component.d.ts.map +1 -0
- package/dist/lib/components/collection/collection-artifact-card.component.js +147 -0
- package/dist/lib/components/collection/collection-artifact-card.component.js.map +1 -0
- package/dist/lib/components/collection/collection-form-modal.component.d.ts +33 -0
- package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -0
- package/dist/lib/components/collection/collection-form-modal.component.js +245 -0
- package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -0
- package/dist/lib/components/collection/collection-tree.component.d.ts +42 -0
- package/dist/lib/components/collection/collection-tree.component.d.ts.map +1 -0
- package/dist/lib/components/collection/collection-tree.component.js +482 -0
- package/dist/lib/components/collection/collection-tree.component.js.map +1 -0
- package/dist/lib/components/collection/collection-view.component.d.ts +31 -0
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -0
- package/dist/lib/components/collection/collection-view.component.js +254 -0
- package/dist/lib/components/collection/collection-view.component.js.map +1 -0
- package/dist/lib/components/collection/collections-full-view.component.d.ts +55 -0
- package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -0
- package/dist/lib/components/collection/collections-full-view.component.js +578 -0
- package/dist/lib/components/collection/collections-full-view.component.js.map +1 -0
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +160 -0
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -0
- package/dist/lib/components/conversation/conversation-chat-area.component.js +891 -0
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -0
- package/dist/lib/components/conversation/conversation-list.component.d.ts +29 -0
- package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -0
- package/dist/lib/components/conversation/conversation-list.component.js +255 -0
- package/dist/lib/components/conversation/conversation-list.component.js.map +1 -0
- package/dist/lib/components/dialogs/input-dialog.component.d.ts +17 -0
- package/dist/lib/components/dialogs/input-dialog.component.d.ts.map +1 -0
- package/dist/lib/components/dialogs/input-dialog.component.js +122 -0
- package/dist/lib/components/dialogs/input-dialog.component.js.map +1 -0
- package/dist/lib/components/export/export-modal.component.d.ts +37 -0
- package/dist/lib/components/export/export-modal.component.d.ts.map +1 -0
- package/dist/lib/components/export/export-modal.component.js +414 -0
- package/dist/lib/components/export/export-modal.component.js.map +1 -0
- package/dist/lib/components/library/library-full-view.component.d.ts +36 -0
- package/dist/lib/components/library/library-full-view.component.d.ts.map +1 -0
- package/dist/lib/components/library/library-full-view.component.js +270 -0
- package/dist/lib/components/library/library-full-view.component.js.map +1 -0
- package/dist/lib/components/members/members-modal.component.d.ts +42 -0
- package/dist/lib/components/members/members-modal.component.d.ts.map +1 -0
- package/dist/lib/components/members/members-modal.component.js +352 -0
- package/dist/lib/components/members/members-modal.component.js.map +1 -0
- package/dist/lib/components/mention/mention-dropdown.component.d.ts +44 -0
- package/dist/lib/components/mention/mention-dropdown.component.d.ts.map +1 -0
- package/dist/lib/components/mention/mention-dropdown.component.js +194 -0
- package/dist/lib/components/mention/mention-dropdown.component.js.map +1 -0
- package/dist/lib/components/message/message-input.component.d.ts +137 -0
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -0
- package/dist/lib/components/message/message-input.component.js +1159 -0
- package/dist/lib/components/message/message-input.component.js.map +1 -0
- package/dist/lib/components/message/message-item.component.d.ts +140 -0
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -0
- package/dist/lib/components/message/message-item.component.js +817 -0
- package/dist/lib/components/message/message-item.component.js.map +1 -0
- package/dist/lib/components/message/message-list.component.d.ts +77 -0
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -0
- package/dist/lib/components/message/message-list.component.js +316 -0
- package/dist/lib/components/message/message-list.component.js.map +1 -0
- package/dist/lib/components/navigation/conversation-navigation.component.d.ts +13 -0
- package/dist/lib/components/navigation/conversation-navigation.component.d.ts.map +1 -0
- package/dist/lib/components/navigation/conversation-navigation.component.js +88 -0
- package/dist/lib/components/navigation/conversation-navigation.component.js.map +1 -0
- package/dist/lib/components/notification/activity-indicator.component.d.ts +11 -0
- package/dist/lib/components/notification/activity-indicator.component.d.ts.map +1 -0
- package/dist/lib/components/notification/activity-indicator.component.js +56 -0
- package/dist/lib/components/notification/activity-indicator.component.js.map +1 -0
- package/dist/lib/components/notification/notification-badge.component.d.ts +27 -0
- package/dist/lib/components/notification/notification-badge.component.d.ts.map +1 -0
- package/dist/lib/components/notification/notification-badge.component.js +160 -0
- package/dist/lib/components/notification/notification-badge.component.js.map +1 -0
- package/dist/lib/components/project/project-form-modal.component.d.ts +34 -0
- package/dist/lib/components/project/project-form-modal.component.d.ts.map +1 -0
- package/dist/lib/components/project/project-form-modal.component.js +357 -0
- package/dist/lib/components/project/project-form-modal.component.js.map +1 -0
- package/dist/lib/components/project/project-selector.component.d.ts +36 -0
- package/dist/lib/components/project/project-selector.component.d.ts.map +1 -0
- package/dist/lib/components/project/project-selector.component.js +317 -0
- package/dist/lib/components/project/project-selector.component.js.map +1 -0
- package/dist/lib/components/search/search-panel.component.d.ts +120 -0
- package/dist/lib/components/search/search-panel.component.d.ts.map +1 -0
- package/dist/lib/components/search/search-panel.component.js +714 -0
- package/dist/lib/components/search/search-panel.component.js.map +1 -0
- package/dist/lib/components/share/share-modal.component.d.ts +46 -0
- package/dist/lib/components/share/share-modal.component.d.ts.map +1 -0
- package/dist/lib/components/share/share-modal.component.js +431 -0
- package/dist/lib/components/share/share-modal.component.js.map +1 -0
- package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts +18 -0
- package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts.map +1 -0
- package/dist/lib/components/sidebar/conversation-sidebar.component.js +81 -0
- package/dist/lib/components/sidebar/conversation-sidebar.component.js.map +1 -0
- package/dist/lib/components/task/task-form-modal.component.d.ts +42 -0
- package/dist/lib/components/task/task-form-modal.component.d.ts.map +1 -0
- package/dist/lib/components/task/task-form-modal.component.js +329 -0
- package/dist/lib/components/task/task-form-modal.component.js.map +1 -0
- package/dist/lib/components/task/task-item.component.d.ts +22 -0
- package/dist/lib/components/task/task-item.component.d.ts.map +1 -0
- package/dist/lib/components/task/task-item.component.js +234 -0
- package/dist/lib/components/task/task-item.component.js.map +1 -0
- package/dist/lib/components/task/task-list.component.d.ts +32 -0
- package/dist/lib/components/task/task-list.component.d.ts.map +1 -0
- package/dist/lib/components/task/task-list.component.js +290 -0
- package/dist/lib/components/task/task-list.component.js.map +1 -0
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +27 -0
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -0
- package/dist/lib/components/tasks/tasks-dropdown.component.js +254 -0
- package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -0
- package/dist/lib/components/thread/thread-panel.component.d.ts +65 -0
- package/dist/lib/components/thread/thread-panel.component.d.ts.map +1 -0
- package/dist/lib/components/thread/thread-panel.component.js +325 -0
- package/dist/lib/components/thread/thread-panel.component.js.map +1 -0
- package/dist/lib/components/toast/toast.component.d.ts +26 -0
- package/dist/lib/components/toast/toast.component.d.ts.map +1 -0
- package/dist/lib/components/toast/toast.component.js +108 -0
- package/dist/lib/components/toast/toast.component.js.map +1 -0
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +75 -0
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -0
- package/dist/lib/components/workspace/conversation-workspace.component.js +299 -0
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -0
- package/dist/lib/conversations.module.d.ts +62 -0
- package/dist/lib/conversations.module.d.ts.map +1 -0
- package/dist/lib/conversations.module.js +248 -0
- package/dist/lib/conversations.module.js.map +1 -0
- package/dist/lib/directives/search-shortcut.directive.d.ts +17 -0
- package/dist/lib/directives/search-shortcut.directive.d.ts.map +1 -0
- package/dist/lib/directives/search-shortcut.directive.js +39 -0
- package/dist/lib/directives/search-shortcut.directive.js.map +1 -0
- package/dist/lib/models/conversation-state.model.d.ts +72 -0
- package/dist/lib/models/conversation-state.model.d.ts.map +1 -0
- package/dist/lib/models/conversation-state.model.js +2 -0
- package/dist/lib/models/conversation-state.model.js.map +1 -0
- package/dist/lib/models/notification.model.d.ts +89 -0
- package/dist/lib/models/notification.model.d.ts.map +1 -0
- package/dist/lib/models/notification.model.js +11 -0
- package/dist/lib/models/notification.model.js.map +1 -0
- package/dist/lib/services/active-tasks.service.d.ts +65 -0
- package/dist/lib/services/active-tasks.service.d.ts.map +1 -0
- package/dist/lib/services/active-tasks.service.js +95 -0
- package/dist/lib/services/active-tasks.service.js.map +1 -0
- package/dist/lib/services/agent-state.service.d.ts +78 -0
- package/dist/lib/services/agent-state.service.d.ts.map +1 -0
- package/dist/lib/services/agent-state.service.js +213 -0
- package/dist/lib/services/agent-state.service.js.map +1 -0
- package/dist/lib/services/artifact-state.service.d.ts +114 -0
- package/dist/lib/services/artifact-state.service.d.ts.map +1 -0
- package/dist/lib/services/artifact-state.service.js +288 -0
- package/dist/lib/services/artifact-state.service.js.map +1 -0
- package/dist/lib/services/conversation-agent.service.d.ts +79 -0
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -0
- package/dist/lib/services/conversation-agent.service.js +259 -0
- package/dist/lib/services/conversation-agent.service.js.map +1 -0
- package/dist/lib/services/conversation-state.service.d.ts +122 -0
- package/dist/lib/services/conversation-state.service.d.ts.map +1 -0
- package/dist/lib/services/conversation-state.service.js +255 -0
- package/dist/lib/services/conversation-state.service.js.map +1 -0
- package/dist/lib/services/dialog.service.d.ts +54 -0
- package/dist/lib/services/dialog.service.d.ts.map +1 -0
- package/dist/lib/services/dialog.service.js +157 -0
- package/dist/lib/services/dialog.service.js.map +1 -0
- package/dist/lib/services/export.service.d.ts +25 -0
- package/dist/lib/services/export.service.d.ts.map +1 -0
- package/dist/lib/services/export.service.js +237 -0
- package/dist/lib/services/export.service.js.map +1 -0
- package/dist/lib/services/mention-autocomplete.service.d.ts +59 -0
- package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -0
- package/dist/lib/services/mention-autocomplete.service.js +160 -0
- package/dist/lib/services/mention-autocomplete.service.js.map +1 -0
- package/dist/lib/services/mention-parser.service.d.ts +46 -0
- package/dist/lib/services/mention-parser.service.d.ts.map +1 -0
- package/dist/lib/services/mention-parser.service.js +156 -0
- package/dist/lib/services/mention-parser.service.js.map +1 -0
- package/dist/lib/services/notification.service.d.ts +108 -0
- package/dist/lib/services/notification.service.d.ts.map +1 -0
- package/dist/lib/services/notification.service.js +431 -0
- package/dist/lib/services/notification.service.js.map +1 -0
- package/dist/lib/services/search.service.d.ts +144 -0
- package/dist/lib/services/search.service.d.ts.map +1 -0
- package/dist/lib/services/search.service.js +370 -0
- package/dist/lib/services/search.service.js.map +1 -0
- package/dist/lib/services/toast.service.d.ts +46 -0
- package/dist/lib/services/toast.service.d.ts.map +1 -0
- package/dist/lib/services/toast.service.js +76 -0
- package/dist/lib/services/toast.service.js.map +1 -0
- package/dist/public-api.d.ts +42 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +49 -0
- package/dist/public-api.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,1159 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
|
|
2
|
+
import { Metadata, RunView } from '@memberjunction/core';
|
|
3
|
+
import { GraphQLAIClient } from '@memberjunction/graphql-dataprovider';
|
|
4
|
+
import { AIEngineBase } from '@memberjunction/ai-engine-base';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "../../services/dialog.service";
|
|
7
|
+
import * as i2 from "../../services/toast.service";
|
|
8
|
+
import * as i3 from "../../services/conversation-agent.service";
|
|
9
|
+
import * as i4 from "../../services/conversation-state.service";
|
|
10
|
+
import * as i5 from "../../services/active-tasks.service";
|
|
11
|
+
import * as i6 from "../../services/mention-autocomplete.service";
|
|
12
|
+
import * as i7 from "../../services/mention-parser.service";
|
|
13
|
+
import * as i8 from "@angular/common";
|
|
14
|
+
import * as i9 from "@angular/forms";
|
|
15
|
+
import * as i10 from "../mention/mention-dropdown.component";
|
|
16
|
+
const _c0 = ["messageTextarea"];
|
|
17
|
+
function MessageInputComponent_div_6_Template(rf, ctx) { if (rf & 1) {
|
|
18
|
+
i0.ɵɵelementStart(0, "div", 10);
|
|
19
|
+
i0.ɵɵelement(1, "i", 11);
|
|
20
|
+
i0.ɵɵelementStart(2, "span");
|
|
21
|
+
i0.ɵɵtext(3, "AI is responding...");
|
|
22
|
+
i0.ɵɵelementEnd()();
|
|
23
|
+
} }
|
|
24
|
+
export class MessageInputComponent {
|
|
25
|
+
dialogService;
|
|
26
|
+
toastService;
|
|
27
|
+
agentService;
|
|
28
|
+
conversationState;
|
|
29
|
+
activeTasks;
|
|
30
|
+
mentionAutocomplete;
|
|
31
|
+
mentionParser;
|
|
32
|
+
conversationId;
|
|
33
|
+
currentUser;
|
|
34
|
+
disabled = false;
|
|
35
|
+
placeholder = 'Type a message... (Ctrl+Enter to send)';
|
|
36
|
+
parentMessageId; // Optional: for replying in threads
|
|
37
|
+
conversationHistory = []; // For agent context
|
|
38
|
+
messageSent = new EventEmitter();
|
|
39
|
+
agentResponse = new EventEmitter();
|
|
40
|
+
agentRunDetected = new EventEmitter();
|
|
41
|
+
artifactCreated = new EventEmitter();
|
|
42
|
+
conversationRenamed = new EventEmitter();
|
|
43
|
+
messageTextarea;
|
|
44
|
+
messageText = '';
|
|
45
|
+
isSending = false;
|
|
46
|
+
isProcessing = false; // True when waiting for agent/naming response
|
|
47
|
+
converationManagerAgent = null;
|
|
48
|
+
// Mention autocomplete state
|
|
49
|
+
showMentionDropdown = false;
|
|
50
|
+
mentionSuggestions = [];
|
|
51
|
+
mentionDropdownPosition = { top: 0, left: 0 };
|
|
52
|
+
mentionDropdownShowAbove = false; // Controls transform direction
|
|
53
|
+
mentionStartIndex = -1;
|
|
54
|
+
mentionQuery = '';
|
|
55
|
+
constructor(dialogService, toastService, agentService, conversationState, activeTasks, mentionAutocomplete, mentionParser) {
|
|
56
|
+
this.dialogService = dialogService;
|
|
57
|
+
this.toastService = toastService;
|
|
58
|
+
this.agentService = agentService;
|
|
59
|
+
this.conversationState = conversationState;
|
|
60
|
+
this.activeTasks = activeTasks;
|
|
61
|
+
this.mentionAutocomplete = mentionAutocomplete;
|
|
62
|
+
this.mentionParser = mentionParser;
|
|
63
|
+
}
|
|
64
|
+
async ngOnInit() {
|
|
65
|
+
this.converationManagerAgent = await this.agentService.getConversationManagerAgent();
|
|
66
|
+
// Initialize mention autocomplete
|
|
67
|
+
await this.mentionAutocomplete.initialize(this.currentUser);
|
|
68
|
+
}
|
|
69
|
+
get canSend() {
|
|
70
|
+
return !this.disabled && !this.isSending && this.messageText.trim().length > 0;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Handle input events to detect @ mentions
|
|
74
|
+
*/
|
|
75
|
+
onInput(event) {
|
|
76
|
+
const textarea = event.target;
|
|
77
|
+
const cursorPos = textarea.selectionStart;
|
|
78
|
+
const text = textarea.value;
|
|
79
|
+
// Check if we're typing after an @ symbol
|
|
80
|
+
const textBeforeCursor = text.substring(0, cursorPos);
|
|
81
|
+
const mentionMatch = textBeforeCursor.match(/@(\S*)$/);
|
|
82
|
+
if (mentionMatch) {
|
|
83
|
+
// We found an @ mention being typed
|
|
84
|
+
this.mentionStartIndex = cursorPos - mentionMatch[0].length;
|
|
85
|
+
this.mentionQuery = mentionMatch[1] || '';
|
|
86
|
+
console.log('[MentionInput] Detected @mention:', this.mentionQuery);
|
|
87
|
+
// Get suggestions
|
|
88
|
+
this.mentionSuggestions = this.mentionAutocomplete.getSuggestions(this.mentionQuery);
|
|
89
|
+
console.log('[MentionInput] Got suggestions:', this.mentionSuggestions.length, this.mentionSuggestions);
|
|
90
|
+
// Calculate dropdown position
|
|
91
|
+
this.calculateDropdownPosition(textarea);
|
|
92
|
+
// Show dropdown if we have suggestions OR to show empty state
|
|
93
|
+
this.showMentionDropdown = true;
|
|
94
|
+
console.log('[MentionInput] Showing dropdown:', this.showMentionDropdown);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// No @ mention, close dropdown
|
|
98
|
+
this.closeMentionDropdown();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Handle keydown events in the textarea
|
|
103
|
+
* - Enter alone: Send message (unless dropdown is open)
|
|
104
|
+
* - Shift+Enter: Add new line
|
|
105
|
+
* - Arrow keys, Tab, Escape: Handle mention dropdown if open
|
|
106
|
+
*/
|
|
107
|
+
onKeyDown(event) {
|
|
108
|
+
// If mention dropdown is open, let it handle certain keys
|
|
109
|
+
if (this.showMentionDropdown) {
|
|
110
|
+
if (['ArrowDown', 'ArrowUp', 'Enter', 'Tab', 'Escape'].includes(event.key)) {
|
|
111
|
+
// These keys are handled by the dropdown component
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Regular key handling
|
|
116
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
117
|
+
// Prevent default behavior (adding newline)
|
|
118
|
+
event.preventDefault();
|
|
119
|
+
// Send the message
|
|
120
|
+
this.onSend();
|
|
121
|
+
}
|
|
122
|
+
// If Shift+Enter, allow default behavior (add newline)
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Calculate position for mention dropdown
|
|
126
|
+
* Keeps dropdown anchored to textarea edge regardless of content size
|
|
127
|
+
*/
|
|
128
|
+
calculateDropdownPosition(textarea) {
|
|
129
|
+
const rect = textarea.getBoundingClientRect();
|
|
130
|
+
const container = textarea.closest('.message-input-container');
|
|
131
|
+
const containerRect = container?.getBoundingClientRect();
|
|
132
|
+
if (!containerRect) {
|
|
133
|
+
// Fallback to absolute positioning
|
|
134
|
+
this.mentionDropdownPosition = {
|
|
135
|
+
top: rect.bottom + window.scrollY + 4,
|
|
136
|
+
left: rect.left + window.scrollX
|
|
137
|
+
};
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// Check if there's enough space below the textarea
|
|
141
|
+
const spaceBelow = window.innerHeight - rect.bottom;
|
|
142
|
+
const spaceAbove = rect.top;
|
|
143
|
+
this.mentionDropdownShowAbove = spaceBelow < 200 && spaceAbove > spaceBelow;
|
|
144
|
+
// Position relative to the container
|
|
145
|
+
// Always anchor to the textarea edge so dropdown stays in place as content changes
|
|
146
|
+
if (this.mentionDropdownShowAbove) {
|
|
147
|
+
// Show above the textarea - anchor to the TOP of the textarea
|
|
148
|
+
// CSS transform will make it grow upward from this anchor point
|
|
149
|
+
this.mentionDropdownPosition = {
|
|
150
|
+
top: rect.top - containerRect.top - 4, // Anchor just above textarea
|
|
151
|
+
left: rect.left - containerRect.left
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Show below the textarea (default) - anchor to the BOTTOM of the textarea
|
|
156
|
+
this.mentionDropdownPosition = {
|
|
157
|
+
top: rect.bottom - containerRect.top + 4,
|
|
158
|
+
left: rect.left - containerRect.left
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Handle mention suggestion selection
|
|
164
|
+
*/
|
|
165
|
+
onMentionSelected(suggestion) {
|
|
166
|
+
if (this.mentionStartIndex === -1)
|
|
167
|
+
return;
|
|
168
|
+
const textarea = this.messageTextarea.nativeElement;
|
|
169
|
+
const cursorPos = textarea.selectionStart;
|
|
170
|
+
// Replace the @mention text with the selected name
|
|
171
|
+
const beforeMention = this.messageText.substring(0, this.mentionStartIndex);
|
|
172
|
+
const afterMention = this.messageText.substring(cursorPos);
|
|
173
|
+
// If name has spaces, wrap in quotes
|
|
174
|
+
const mentionText = suggestion.displayName.includes(' ')
|
|
175
|
+
? `@"${suggestion.displayName}" `
|
|
176
|
+
: `@${suggestion.displayName} `;
|
|
177
|
+
this.messageText = beforeMention + mentionText + afterMention;
|
|
178
|
+
// Close dropdown
|
|
179
|
+
this.closeMentionDropdown();
|
|
180
|
+
// Set cursor position after the mention
|
|
181
|
+
const newCursorPos = beforeMention.length + mentionText.length;
|
|
182
|
+
setTimeout(() => {
|
|
183
|
+
textarea.selectionStart = newCursorPos;
|
|
184
|
+
textarea.selectionEnd = newCursorPos;
|
|
185
|
+
textarea.focus();
|
|
186
|
+
}, 0);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Close mention dropdown
|
|
190
|
+
*/
|
|
191
|
+
closeMentionDropdown() {
|
|
192
|
+
this.showMentionDropdown = false;
|
|
193
|
+
this.mentionSuggestions = [];
|
|
194
|
+
this.mentionStartIndex = -1;
|
|
195
|
+
this.mentionQuery = '';
|
|
196
|
+
}
|
|
197
|
+
async onSend() {
|
|
198
|
+
if (!this.canSend)
|
|
199
|
+
return;
|
|
200
|
+
this.isSending = true;
|
|
201
|
+
try {
|
|
202
|
+
const md = new Metadata();
|
|
203
|
+
const detail = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
204
|
+
detail.ConversationID = this.conversationId;
|
|
205
|
+
detail.Message = this.messageText.trim();
|
|
206
|
+
detail.Role = 'User';
|
|
207
|
+
// Parse mentions from message (not stored, used for routing only)
|
|
208
|
+
const mentionResult = this.mentionParser.parseMentions(detail.Message, this.mentionAutocomplete.getAvailableAgents(), this.mentionAutocomplete.getAvailableUsers());
|
|
209
|
+
console.log('[MentionInput] Parsing message for routing:', detail.Message);
|
|
210
|
+
console.log('[MentionInput] Found mentions:', mentionResult);
|
|
211
|
+
console.log('[MentionInput] Agent mention:', mentionResult.agentMention);
|
|
212
|
+
// Set ParentID if this is a thread reply
|
|
213
|
+
if (this.parentMessageId) {
|
|
214
|
+
detail.ParentID = this.parentMessageId;
|
|
215
|
+
}
|
|
216
|
+
const saved = await detail.Save();
|
|
217
|
+
if (saved) {
|
|
218
|
+
this.messageSent.emit(detail);
|
|
219
|
+
this.messageText = '';
|
|
220
|
+
// Check if this is the first message in the conversation
|
|
221
|
+
const isFirstMessage = this.conversationHistory.length === 0;
|
|
222
|
+
// Determine routing: @mention > last agent context > Conversation Manager
|
|
223
|
+
if (mentionResult.agentMention) {
|
|
224
|
+
// Direct @mention - skip Conversation Manager, invoke agent directly
|
|
225
|
+
console.log('🎯 Direct @mention detected, bypassing Conversation Manager');
|
|
226
|
+
if (isFirstMessage) {
|
|
227
|
+
Promise.all([
|
|
228
|
+
this.invokeAgentDirectly(detail, mentionResult.agentMention, this.conversationId),
|
|
229
|
+
this.nameConversation(detail.Message)
|
|
230
|
+
]);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
this.invokeAgentDirectly(detail, mentionResult.agentMention, this.conversationId);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// Check if user is replying to an agent (implicit continuation)
|
|
238
|
+
const lastAIMessage = this.conversationHistory
|
|
239
|
+
.slice()
|
|
240
|
+
.reverse()
|
|
241
|
+
.find(msg => msg.Role === 'AI' &&
|
|
242
|
+
msg.AgentID &&
|
|
243
|
+
msg.AgentID !== this.converationManagerAgent?.ID);
|
|
244
|
+
if (lastAIMessage && lastAIMessage.AgentID) {
|
|
245
|
+
// Continue with same agent - skip Conversation Manager
|
|
246
|
+
console.log('🔄 Implicit continuation detected, continuing with last agent');
|
|
247
|
+
if (isFirstMessage) {
|
|
248
|
+
Promise.all([
|
|
249
|
+
this.continueWithAgent(detail, lastAIMessage.AgentID, this.conversationId),
|
|
250
|
+
this.nameConversation(detail.Message)
|
|
251
|
+
]);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
this.continueWithAgent(detail, lastAIMessage.AgentID, this.conversationId);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// No context - use Conversation Manager
|
|
259
|
+
console.log('🤖 No agent context, using Conversation Manager');
|
|
260
|
+
if (isFirstMessage) {
|
|
261
|
+
Promise.all([
|
|
262
|
+
this.processMessageThroughAgent(detail, mentionResult),
|
|
263
|
+
this.nameConversation(detail.Message)
|
|
264
|
+
]);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
this.processMessageThroughAgent(detail, mentionResult);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// Focus back on textarea
|
|
272
|
+
setTimeout(() => {
|
|
273
|
+
if (this.messageTextarea && this.messageTextarea.nativeElement) {
|
|
274
|
+
this.messageTextarea.nativeElement.focus();
|
|
275
|
+
}
|
|
276
|
+
}, 100);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
console.error('Failed to send message:', detail.LatestResult?.Message);
|
|
280
|
+
this.toastService.error('Failed to send message. Please try again.');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
console.error('Error sending message:', error);
|
|
285
|
+
this.toastService.error('Error sending message. Please try again.');
|
|
286
|
+
}
|
|
287
|
+
finally {
|
|
288
|
+
this.isSending = false;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Create a progress callback for agent execution
|
|
293
|
+
* This callback updates both the active task and the ConversationDetail message
|
|
294
|
+
* IMPORTANT: Filters by agentRunId to prevent cross-contamination when multiple agents run in parallel
|
|
295
|
+
*/
|
|
296
|
+
createProgressCallback(conversationDetailId, agentName) {
|
|
297
|
+
return async (progress) => {
|
|
298
|
+
// Extract agentRunId from progress metadata
|
|
299
|
+
const progressAgentRunId = progress.metadata?.agentRunId;
|
|
300
|
+
// Format progress message with visual indicator
|
|
301
|
+
const progressText = progress.message;
|
|
302
|
+
// Update the active task with progress details (if it exists)
|
|
303
|
+
this.activeTasks.updateStatusByConversationDetailId(conversationDetailId, progressText);
|
|
304
|
+
// Update the ConversationDetail message in real-time
|
|
305
|
+
try {
|
|
306
|
+
const md = new Metadata();
|
|
307
|
+
const conversationDetail = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
308
|
+
if (await conversationDetail.Load(conversationDetailId)) {
|
|
309
|
+
// Skip progress updates if message is already complete
|
|
310
|
+
if (conversationDetail.Status === 'Complete') {
|
|
311
|
+
console.log(`[${agentName}] Skipping progress update - message already complete`);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
// CRITICAL: Only update if agentRunIds match (prevents cross-contamination)
|
|
315
|
+
const storedAgentRunId = conversationDetail.AgentRunID;
|
|
316
|
+
// If AgentRunID not yet set, set it from the first progress update
|
|
317
|
+
if (!storedAgentRunId && progressAgentRunId) {
|
|
318
|
+
conversationDetail.AgentRunID = progressAgentRunId;
|
|
319
|
+
console.log(`[${agentName}] Setting AgentRunID from progress update:`, progressAgentRunId);
|
|
320
|
+
// Emit event to parent so it can load the agent run into the map immediately
|
|
321
|
+
this.agentRunDetected.emit({
|
|
322
|
+
conversationDetailId,
|
|
323
|
+
agentRunId: progressAgentRunId
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
// If we have both IDs, verify they match before updating
|
|
327
|
+
else if (progressAgentRunId && storedAgentRunId) {
|
|
328
|
+
if (progressAgentRunId !== storedAgentRunId) {
|
|
329
|
+
console.log(`[${agentName}] Skipping progress update - agentRunId mismatch:`, {
|
|
330
|
+
progressAgentRunId,
|
|
331
|
+
storedAgentRunId,
|
|
332
|
+
conversationDetailId
|
|
333
|
+
});
|
|
334
|
+
return; // Skip this update - it's for a different agent run
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
conversationDetail.Message = progressText;
|
|
338
|
+
await conversationDetail.Save();
|
|
339
|
+
// Emit update to trigger UI refresh
|
|
340
|
+
this.messageSent.emit(conversationDetail);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
console.warn('Failed to save progress update to ConversationDetail:', error);
|
|
345
|
+
}
|
|
346
|
+
console.log(`[${agentName}] Progress: ${progress.step} - ${progress.message} (${progress.percentage}%)`, {
|
|
347
|
+
agentRunId: progressAgentRunId,
|
|
348
|
+
conversationDetailId
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Process the message through agents (multi-stage: Conversation Manager -> possible sub-agent)
|
|
354
|
+
* Only called when there's no @mention and no implicit agent context
|
|
355
|
+
*/
|
|
356
|
+
async processMessageThroughAgent(userMessage, mentionResult) {
|
|
357
|
+
let taskId = null;
|
|
358
|
+
let conversationManagerMessage = null;
|
|
359
|
+
// CRITICAL: Capture conversationId from user message at start
|
|
360
|
+
// This prevents race condition when user switches conversations during async processing
|
|
361
|
+
const conversationId = userMessage.ConversationID;
|
|
362
|
+
try {
|
|
363
|
+
// Create AI message for Conversation Manager BEFORE invoking
|
|
364
|
+
const md = new Metadata();
|
|
365
|
+
conversationManagerMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
366
|
+
conversationManagerMessage.ConversationID = conversationId;
|
|
367
|
+
conversationManagerMessage.Role = 'AI';
|
|
368
|
+
conversationManagerMessage.Message = '⏳ Starting...';
|
|
369
|
+
conversationManagerMessage.ParentID = userMessage.ID;
|
|
370
|
+
conversationManagerMessage.Status = 'In-Progress';
|
|
371
|
+
conversationManagerMessage.HiddenToUser = false;
|
|
372
|
+
// Use the preloaded Conversation Manager agent instead of looking it up
|
|
373
|
+
if (this.converationManagerAgent?.ID) {
|
|
374
|
+
conversationManagerMessage.AgentID = this.converationManagerAgent.ID;
|
|
375
|
+
}
|
|
376
|
+
await conversationManagerMessage.Save();
|
|
377
|
+
this.messageSent.emit(conversationManagerMessage);
|
|
378
|
+
// Use Conversation Manager to evaluate and route
|
|
379
|
+
// Stage 1: Conversation Manager evaluates the message
|
|
380
|
+
taskId = this.activeTasks.add({
|
|
381
|
+
agentName: 'Conversation Manager',
|
|
382
|
+
status: 'Evaluating message...',
|
|
383
|
+
relatedMessageId: userMessage.ID,
|
|
384
|
+
conversationDetailId: conversationManagerMessage.ID
|
|
385
|
+
});
|
|
386
|
+
const result = await this.agentService.processMessage(conversationId, userMessage, this.conversationHistory, conversationManagerMessage.ID, this.createProgressCallback(conversationManagerMessage.ID, 'Conversation Manager'));
|
|
387
|
+
// Remove Conversation Manager from active tasks
|
|
388
|
+
if (taskId) {
|
|
389
|
+
this.activeTasks.remove(taskId);
|
|
390
|
+
taskId = null;
|
|
391
|
+
}
|
|
392
|
+
if (!result || !result.success) {
|
|
393
|
+
// Evaluation failed
|
|
394
|
+
conversationManagerMessage.Status = 'Error';
|
|
395
|
+
conversationManagerMessage.Message = `❌ Evaluation failed`;
|
|
396
|
+
conversationManagerMessage.Error = result?.agentRun?.ErrorMessage || 'Agent evaluation failed';
|
|
397
|
+
await conversationManagerMessage.Save();
|
|
398
|
+
this.messageSent.emit(conversationManagerMessage);
|
|
399
|
+
userMessage.Status = 'Complete';
|
|
400
|
+
await userMessage.Save();
|
|
401
|
+
this.messageSent.emit(userMessage);
|
|
402
|
+
console.warn('⚠️ Conversation Manager failed:', result?.agentRun?.ErrorMessage);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
console.log('🤖 Conversation Manager Response:', {
|
|
406
|
+
finalStep: result.agentRun.FinalStep,
|
|
407
|
+
hasPayload: !!result.payload,
|
|
408
|
+
hasMessage: !!result.agentRun.Message
|
|
409
|
+
});
|
|
410
|
+
// Stage 2: Check for sub-agent invocation
|
|
411
|
+
if (result.agentRun.FinalStep === 'Success' && result.payload?.invokeAgent) {
|
|
412
|
+
// Reuse the existing conversationManagerMessage instead of creating new ones
|
|
413
|
+
await this.handleSubAgentInvocation(userMessage, result, this.conversationId, conversationManagerMessage);
|
|
414
|
+
}
|
|
415
|
+
// Stage 3: Direct chat response from Conversation Manager
|
|
416
|
+
else if (result.agentRun.FinalStep === 'Chat' && result.agentRun.Message) {
|
|
417
|
+
// Update the existing message with the response
|
|
418
|
+
conversationManagerMessage.Message = result.agentRun.Message;
|
|
419
|
+
conversationManagerMessage.Status = 'Complete';
|
|
420
|
+
if (result.agentRun.ID) {
|
|
421
|
+
conversationManagerMessage.AgentRunID = result.agentRun.ID;
|
|
422
|
+
}
|
|
423
|
+
await conversationManagerMessage.Save();
|
|
424
|
+
this.messageSent.emit(conversationManagerMessage);
|
|
425
|
+
// Handle artifacts if any
|
|
426
|
+
if (result.payload && Object.keys(result.payload).length > 0) {
|
|
427
|
+
await this.createArtifactFromPayload(result.payload, conversationManagerMessage, result.agentRun.AgentID);
|
|
428
|
+
console.log('🎨 Artifact created and linked to Conversation Manager message');
|
|
429
|
+
this.messageSent.emit(conversationManagerMessage);
|
|
430
|
+
}
|
|
431
|
+
userMessage.Status = 'Complete';
|
|
432
|
+
await userMessage.Save();
|
|
433
|
+
this.messageSent.emit(userMessage);
|
|
434
|
+
}
|
|
435
|
+
// Stage 4: Silent observation - check for agent continuity
|
|
436
|
+
else {
|
|
437
|
+
console.log('🔇 Conversation Manager chose to observe silently');
|
|
438
|
+
// Hide the Conversation Manager message
|
|
439
|
+
conversationManagerMessage.HiddenToUser = true;
|
|
440
|
+
conversationManagerMessage.Status = 'Complete';
|
|
441
|
+
await conversationManagerMessage.Save();
|
|
442
|
+
this.messageSent.emit(conversationManagerMessage);
|
|
443
|
+
await this.handleSilentObservation(userMessage, this.conversationId);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
console.error('❌ Error processing message through agents:', error);
|
|
448
|
+
// Update conversationManagerMessage status to Error
|
|
449
|
+
if (conversationManagerMessage && conversationManagerMessage.ID) {
|
|
450
|
+
conversationManagerMessage.Status = 'Error';
|
|
451
|
+
conversationManagerMessage.Message = `❌ Error: ${String(error)}`;
|
|
452
|
+
conversationManagerMessage.Error = String(error);
|
|
453
|
+
await conversationManagerMessage.Save();
|
|
454
|
+
this.messageSent.emit(conversationManagerMessage);
|
|
455
|
+
}
|
|
456
|
+
// Mark user message as complete
|
|
457
|
+
userMessage.Status = 'Complete';
|
|
458
|
+
await userMessage.Save();
|
|
459
|
+
this.messageSent.emit(userMessage);
|
|
460
|
+
// Clean up active task
|
|
461
|
+
if (taskId) {
|
|
462
|
+
this.activeTasks.remove(taskId);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Handle sub-agent invocation based on Conversation Manager's payload
|
|
468
|
+
* Reuses the existing conversationManagerMessage to avoid creating multiple records
|
|
469
|
+
*/
|
|
470
|
+
async handleSubAgentInvocation(userMessage, managerResult, conversationId, conversationManagerMessage) {
|
|
471
|
+
const payload = managerResult.payload;
|
|
472
|
+
const agentName = payload.invokeAgent;
|
|
473
|
+
const reasoning = payload.reasoning || 'Delegating to specialist agent';
|
|
474
|
+
console.log(`👉 Sub-agent invocation requested: ${agentName}`, { reasoning });
|
|
475
|
+
// Update the existing Conversation Manager message to show delegation
|
|
476
|
+
conversationManagerMessage.Message = `👉 **${agentName}** will handle this request...`;
|
|
477
|
+
conversationManagerMessage.Status = 'Complete';
|
|
478
|
+
// Keep AgentID as Conversation Manager (already set)
|
|
479
|
+
if (managerResult.agentRun.ID) {
|
|
480
|
+
conversationManagerMessage.AgentRunID = managerResult.agentRun.ID;
|
|
481
|
+
}
|
|
482
|
+
await conversationManagerMessage.Save();
|
|
483
|
+
this.messageSent.emit(conversationManagerMessage);
|
|
484
|
+
// Now create a NEW message for the sub-agent execution
|
|
485
|
+
try {
|
|
486
|
+
// Look up the agent to get its ID
|
|
487
|
+
const agent = AIEngineBase.Instance.Agents.find(a => a.Name === agentName);
|
|
488
|
+
// Create AI response message BEFORE invoking agent (for duration tracking)
|
|
489
|
+
const md = new Metadata();
|
|
490
|
+
const agentResponseMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
491
|
+
agentResponseMessage.ConversationID = conversationId;
|
|
492
|
+
agentResponseMessage.Role = 'AI';
|
|
493
|
+
agentResponseMessage.Message = '⏳ Starting...'; // Initial message
|
|
494
|
+
agentResponseMessage.ParentID = conversationManagerMessage.ID; // Thread under delegation message
|
|
495
|
+
agentResponseMessage.Status = 'In-Progress';
|
|
496
|
+
agentResponseMessage.HiddenToUser = false;
|
|
497
|
+
// Set AgentID immediately for proper attribution
|
|
498
|
+
if (agent?.ID) {
|
|
499
|
+
agentResponseMessage.AgentID = agent.ID;
|
|
500
|
+
}
|
|
501
|
+
// Save the record to establish __mj_CreatedAt timestamp
|
|
502
|
+
await agentResponseMessage.Save();
|
|
503
|
+
this.messageSent.emit(agentResponseMessage);
|
|
504
|
+
// Add sub-agent to active tasks
|
|
505
|
+
const newTaskId = this.activeTasks.add({
|
|
506
|
+
agentName: agentName,
|
|
507
|
+
status: 'Starting...',
|
|
508
|
+
relatedMessageId: userMessage.ID,
|
|
509
|
+
conversationDetailId: agentResponseMessage.ID
|
|
510
|
+
});
|
|
511
|
+
// Invoke the sub-agent with progress callback
|
|
512
|
+
const subResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.conversationHistory, reasoning, agentResponseMessage.ID, undefined, // no payload for initial invocation
|
|
513
|
+
this.createProgressCallback(agentResponseMessage.ID, agentName));
|
|
514
|
+
// Remove from active tasks
|
|
515
|
+
this.activeTasks.remove(newTaskId);
|
|
516
|
+
if (subResult && subResult.success) {
|
|
517
|
+
// Update the response message with agent result
|
|
518
|
+
agentResponseMessage.Message = subResult.agentRun?.Message || `✅ **${agentName}** completed`;
|
|
519
|
+
agentResponseMessage.Status = 'Complete';
|
|
520
|
+
// Store the agent ID and AgentRunID for display and tracking
|
|
521
|
+
if (subResult.agentRun.AgentID) {
|
|
522
|
+
agentResponseMessage.AgentID = subResult.agentRun.AgentID;
|
|
523
|
+
}
|
|
524
|
+
if (subResult.agentRun.ID) {
|
|
525
|
+
agentResponseMessage.AgentRunID = subResult.agentRun.ID;
|
|
526
|
+
}
|
|
527
|
+
// Save updates - this sets __mj_UpdatedAt for duration calculation
|
|
528
|
+
await agentResponseMessage.Save();
|
|
529
|
+
this.messageSent.emit(agentResponseMessage);
|
|
530
|
+
// Handle artifacts from sub-agent if any
|
|
531
|
+
if (subResult.payload && Object.keys(subResult.payload).length > 0) {
|
|
532
|
+
await this.createArtifactFromPayload(subResult.payload, agentResponseMessage, subResult.agentRun.AgentID);
|
|
533
|
+
console.log('🎨 Artifact created and linked to sub-agent message:', agentResponseMessage.ID);
|
|
534
|
+
// Re-emit to trigger artifact display
|
|
535
|
+
this.messageSent.emit(agentResponseMessage);
|
|
536
|
+
}
|
|
537
|
+
// Mark user message as complete
|
|
538
|
+
userMessage.Status = 'Complete';
|
|
539
|
+
await userMessage.Save();
|
|
540
|
+
this.messageSent.emit(userMessage);
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
// Sub-agent failed - attempt auto-retry once
|
|
544
|
+
console.log(`⚠️ ${agentName} failed, attempting auto-retry...`);
|
|
545
|
+
// Update delegation message to show retry
|
|
546
|
+
conversationManagerMessage.Message = `👉 **${agentName}** will handle this request...\n\n⚠️ First attempt failed, retrying...`;
|
|
547
|
+
await conversationManagerMessage.Save();
|
|
548
|
+
this.messageSent.emit(conversationManagerMessage);
|
|
549
|
+
// Update the existing agentResponseMessage to show retry status
|
|
550
|
+
agentResponseMessage.Message = 'Retrying...';
|
|
551
|
+
await agentResponseMessage.Save();
|
|
552
|
+
this.messageSent.emit(agentResponseMessage);
|
|
553
|
+
// Retry the sub-agent
|
|
554
|
+
const retryResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.conversationHistory, reasoning, agentResponseMessage.ID, undefined, // no payload for retry
|
|
555
|
+
this.createProgressCallback(agentResponseMessage.ID, `${agentName} (retry)`));
|
|
556
|
+
if (retryResult && retryResult.success) {
|
|
557
|
+
// Retry succeeded - update the same message
|
|
558
|
+
agentResponseMessage.Message = retryResult.agentRun?.Message || `✅ **${agentName}** completed`;
|
|
559
|
+
agentResponseMessage.Status = 'Complete';
|
|
560
|
+
if (retryResult.agentRun.AgentID) {
|
|
561
|
+
agentResponseMessage.AgentID = retryResult.agentRun.AgentID;
|
|
562
|
+
}
|
|
563
|
+
if (retryResult.agentRun.ID) {
|
|
564
|
+
agentResponseMessage.AgentRunID = retryResult.agentRun.ID;
|
|
565
|
+
}
|
|
566
|
+
// Save updates - maintains original CreatedAt for accurate duration
|
|
567
|
+
await agentResponseMessage.Save();
|
|
568
|
+
this.messageSent.emit(agentResponseMessage);
|
|
569
|
+
// Handle artifacts
|
|
570
|
+
if (retryResult.payload && Object.keys(retryResult.payload).length > 0) {
|
|
571
|
+
await this.createArtifactFromPayload(retryResult.payload, agentResponseMessage, retryResult.agentRun.AgentID);
|
|
572
|
+
this.messageSent.emit(agentResponseMessage);
|
|
573
|
+
}
|
|
574
|
+
userMessage.Status = 'Complete';
|
|
575
|
+
await userMessage.Save();
|
|
576
|
+
this.messageSent.emit(userMessage);
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
// Retry also failed - show error with manual retry option
|
|
580
|
+
conversationManagerMessage.Status = 'Error';
|
|
581
|
+
conversationManagerMessage.Message = `❌ **${agentName}** failed after retry\n\n${retryResult?.agentRun?.ErrorMessage || 'Unknown error'}`;
|
|
582
|
+
conversationManagerMessage.Error = retryResult?.agentRun?.ErrorMessage || null;
|
|
583
|
+
await conversationManagerMessage.Save();
|
|
584
|
+
this.messageSent.emit(conversationManagerMessage);
|
|
585
|
+
userMessage.Status = 'Complete'; // Don't mark user message as error
|
|
586
|
+
await userMessage.Save();
|
|
587
|
+
this.messageSent.emit(userMessage);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
catch (error) {
|
|
592
|
+
console.error(`❌ Error invoking sub-agent ${agentName}:`, error);
|
|
593
|
+
conversationManagerMessage.Status = 'Error';
|
|
594
|
+
conversationManagerMessage.Message = `❌ **${agentName}** encountered an error\n\n${String(error)}`;
|
|
595
|
+
conversationManagerMessage.Error = String(error);
|
|
596
|
+
await conversationManagerMessage.Save();
|
|
597
|
+
this.messageSent.emit(conversationManagerMessage);
|
|
598
|
+
userMessage.Status = 'Complete'; // Don't mark user message as error
|
|
599
|
+
await userMessage.Save();
|
|
600
|
+
this.messageSent.emit(userMessage);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Handle silent observation - when Conversation Manager stays silent,
|
|
605
|
+
* check if we should continue with the last agent for iterative refinement
|
|
606
|
+
*/
|
|
607
|
+
async handleSilentObservation(userMessage, conversationId) {
|
|
608
|
+
// Find the last AI message (excluding Conversation Manager) in the conversation history
|
|
609
|
+
const lastAIMessage = this.conversationHistory
|
|
610
|
+
.slice()
|
|
611
|
+
.reverse()
|
|
612
|
+
.find(msg => msg.Role === 'AI' &&
|
|
613
|
+
msg.AgentID &&
|
|
614
|
+
msg.AgentID !== this.converationManagerAgent?.ID);
|
|
615
|
+
if (!lastAIMessage || !lastAIMessage.AgentID) {
|
|
616
|
+
// No previous specialist agent - just mark user message as complete
|
|
617
|
+
console.log('🔇 No previous specialist agent found - marking complete');
|
|
618
|
+
userMessage.Status = 'Complete';
|
|
619
|
+
await userMessage.Save();
|
|
620
|
+
this.messageSent.emit(userMessage);
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
// Load the agent entity to get its name
|
|
624
|
+
const md = new Metadata();
|
|
625
|
+
const rv = new RunView();
|
|
626
|
+
const agentResult = await rv.RunView({
|
|
627
|
+
EntityName: 'AI Agents',
|
|
628
|
+
ExtraFilter: `ID='${lastAIMessage.AgentID}'`,
|
|
629
|
+
ResultType: 'entity_object'
|
|
630
|
+
}, this.currentUser);
|
|
631
|
+
if (!agentResult.Success || !agentResult.Results || agentResult.Results.length === 0) {
|
|
632
|
+
console.warn('⚠️ Could not load previous agent - marking complete');
|
|
633
|
+
userMessage.Status = 'Complete';
|
|
634
|
+
await userMessage.Save();
|
|
635
|
+
this.messageSent.emit(userMessage);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
const previousAgent = agentResult.Results[0];
|
|
639
|
+
const agentName = previousAgent.Name || 'Agent';
|
|
640
|
+
console.log(`🔄 Agent continuity: Continuing with ${agentName} (AgentID: ${lastAIMessage.AgentID})`);
|
|
641
|
+
// Load the OUTPUT artifact from the last agent message
|
|
642
|
+
const artifactResult = await rv.RunView({
|
|
643
|
+
EntityName: 'MJ: Conversation Detail Artifacts',
|
|
644
|
+
ExtraFilter: `ConversationDetailID='${lastAIMessage.ID}' AND Direction='Output'`,
|
|
645
|
+
ResultType: 'entity_object'
|
|
646
|
+
}, this.currentUser);
|
|
647
|
+
let previousPayload = null;
|
|
648
|
+
if (artifactResult.Success && artifactResult.Results && artifactResult.Results.length > 0) {
|
|
649
|
+
// Load the artifact version content
|
|
650
|
+
const junctionRecord = artifactResult.Results[0];
|
|
651
|
+
const versionResult = await rv.RunView({
|
|
652
|
+
EntityName: 'MJ: Artifact Versions',
|
|
653
|
+
ExtraFilter: `ID='${junctionRecord.ArtifactVersionID}'`,
|
|
654
|
+
ResultType: 'entity_object'
|
|
655
|
+
}, this.currentUser);
|
|
656
|
+
if (versionResult.Success && versionResult.Results && versionResult.Results.length > 0) {
|
|
657
|
+
const version = versionResult.Results[0];
|
|
658
|
+
if (version.Content) {
|
|
659
|
+
try {
|
|
660
|
+
previousPayload = JSON.parse(version.Content);
|
|
661
|
+
console.log('📦 Loaded previous OUTPUT artifact as payload for continuity');
|
|
662
|
+
}
|
|
663
|
+
catch (error) {
|
|
664
|
+
console.warn('⚠️ Could not parse previous artifact content:', error);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
// Create status message showing agent continuity
|
|
670
|
+
const statusMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
671
|
+
statusMessage.ConversationID = conversationId;
|
|
672
|
+
statusMessage.Role = 'AI';
|
|
673
|
+
statusMessage.Message = `Continuing with **${agentName}** for refinement...`;
|
|
674
|
+
statusMessage.ParentID = userMessage.ID;
|
|
675
|
+
statusMessage.Status = 'Complete';
|
|
676
|
+
statusMessage.HiddenToUser = false;
|
|
677
|
+
statusMessage.AgentID = this.converationManagerAgent?.ID || null;
|
|
678
|
+
await statusMessage.Save();
|
|
679
|
+
this.messageSent.emit(statusMessage);
|
|
680
|
+
// Add agent to active tasks
|
|
681
|
+
const taskId = this.activeTasks.add({
|
|
682
|
+
agentName: agentName,
|
|
683
|
+
status: 'Processing refinement...',
|
|
684
|
+
relatedMessageId: userMessage.ID,
|
|
685
|
+
conversationDetailId: statusMessage.ID
|
|
686
|
+
});
|
|
687
|
+
try {
|
|
688
|
+
// Invoke the agent with the previous payload
|
|
689
|
+
const continuityResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.conversationHistory, 'Continuing previous work based on user feedback', statusMessage.ID, previousPayload, this.createProgressCallback(statusMessage.ID, agentName));
|
|
690
|
+
// Remove from active tasks
|
|
691
|
+
this.activeTasks.remove(taskId);
|
|
692
|
+
if (continuityResult && continuityResult.success) {
|
|
693
|
+
// Create response message
|
|
694
|
+
const agentResponseMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
695
|
+
agentResponseMessage.ConversationID = conversationId;
|
|
696
|
+
agentResponseMessage.Role = 'AI';
|
|
697
|
+
agentResponseMessage.Message = continuityResult.agentRun?.Message || `✅ **${agentName}** completed refinement`;
|
|
698
|
+
agentResponseMessage.ParentID = statusMessage.ID;
|
|
699
|
+
agentResponseMessage.Status = 'Complete';
|
|
700
|
+
agentResponseMessage.HiddenToUser = false;
|
|
701
|
+
agentResponseMessage.AgentID = lastAIMessage.AgentID;
|
|
702
|
+
await agentResponseMessage.Save();
|
|
703
|
+
this.messageSent.emit(agentResponseMessage);
|
|
704
|
+
// Handle artifacts from agent if any
|
|
705
|
+
if (continuityResult.payload && Object.keys(continuityResult.payload).length > 0) {
|
|
706
|
+
await this.createArtifactFromPayload(continuityResult.payload, agentResponseMessage, lastAIMessage.AgentID);
|
|
707
|
+
console.log('🎨 Artifact created from agent continuity');
|
|
708
|
+
this.messageSent.emit(agentResponseMessage);
|
|
709
|
+
}
|
|
710
|
+
// Mark user message as complete
|
|
711
|
+
userMessage.Status = 'Complete';
|
|
712
|
+
await userMessage.Save();
|
|
713
|
+
this.messageSent.emit(userMessage);
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
// Agent failed
|
|
717
|
+
statusMessage.Status = 'Error';
|
|
718
|
+
statusMessage.Message = `❌ **${agentName}** failed during refinement\n\n${continuityResult?.agentRun?.ErrorMessage || 'Unknown error'}`;
|
|
719
|
+
statusMessage.Error = continuityResult?.agentRun?.ErrorMessage || null;
|
|
720
|
+
await statusMessage.Save();
|
|
721
|
+
this.messageSent.emit(statusMessage);
|
|
722
|
+
userMessage.Status = 'Complete';
|
|
723
|
+
await userMessage.Save();
|
|
724
|
+
this.messageSent.emit(userMessage);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
catch (error) {
|
|
728
|
+
console.error(`❌ Error in agent continuity with ${agentName}:`, error);
|
|
729
|
+
this.activeTasks.remove(taskId);
|
|
730
|
+
statusMessage.Status = 'Error';
|
|
731
|
+
statusMessage.Message = `❌ **${agentName}** encountered an error\n\n${String(error)}`;
|
|
732
|
+
statusMessage.Error = String(error);
|
|
733
|
+
await statusMessage.Save();
|
|
734
|
+
this.messageSent.emit(statusMessage);
|
|
735
|
+
userMessage.Status = 'Complete';
|
|
736
|
+
await userMessage.Save();
|
|
737
|
+
this.messageSent.emit(userMessage);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Handle agent response - create AI message from agent result
|
|
742
|
+
*/
|
|
743
|
+
async handleAgentResponse(userMessage, result, conversationId) {
|
|
744
|
+
if (!result.agentRun.Message)
|
|
745
|
+
return;
|
|
746
|
+
const md = new Metadata();
|
|
747
|
+
const agentMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
748
|
+
agentMessage.ConversationID = conversationId;
|
|
749
|
+
agentMessage.Message = result.agentRun.Message;
|
|
750
|
+
agentMessage.Role = 'AI';
|
|
751
|
+
agentMessage.Status = 'Complete';
|
|
752
|
+
agentMessage.AgentID = this.converationManagerAgent?.ID || null; // Default to Conversation Manager
|
|
753
|
+
// Populate denormalized AgentID for fast lookup
|
|
754
|
+
if (result.agentRun.AgentID) {
|
|
755
|
+
agentMessage.AgentID = result.agentRun.AgentID;
|
|
756
|
+
console.log(`✅ Set AgentID=${result.agentRun.AgentID} for message from agent`);
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
console.warn('⚠️ AgentID not found in agentRun result');
|
|
760
|
+
}
|
|
761
|
+
const saved = await agentMessage.Save();
|
|
762
|
+
if (saved) {
|
|
763
|
+
console.log('💾 Agent response saved');
|
|
764
|
+
// If agent returned a payload, create an artifact version linked to this message
|
|
765
|
+
if (result.payload && Object.keys(result.payload).length > 0) {
|
|
766
|
+
await this.createArtifactFromPayload(result.payload, agentMessage, result.agentRun.AgentID);
|
|
767
|
+
console.log('🎨 Artifact created and linked to conversation detail:', agentMessage.ID);
|
|
768
|
+
}
|
|
769
|
+
this.agentResponse.emit({
|
|
770
|
+
message: agentMessage,
|
|
771
|
+
agentResult: result
|
|
772
|
+
});
|
|
773
|
+
// Mark user message as complete
|
|
774
|
+
userMessage.Status = 'Complete';
|
|
775
|
+
await userMessage.Save();
|
|
776
|
+
this.messageSent.emit(userMessage);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Invoke an agent directly when mentioned with @ symbol
|
|
781
|
+
* Bypasses Conversation Manager completely - no status messages
|
|
782
|
+
*/
|
|
783
|
+
async invokeAgentDirectly(userMessage, agentMention, conversationId) {
|
|
784
|
+
const agentName = agentMention.name;
|
|
785
|
+
// Add agent to active tasks
|
|
786
|
+
const taskId = this.activeTasks.add({
|
|
787
|
+
agentName: agentName,
|
|
788
|
+
status: 'Processing...',
|
|
789
|
+
relatedMessageId: userMessage.ID,
|
|
790
|
+
conversationDetailId: userMessage.ID
|
|
791
|
+
});
|
|
792
|
+
try {
|
|
793
|
+
// Update user message status to In-Progress
|
|
794
|
+
userMessage.Status = 'In-Progress';
|
|
795
|
+
await userMessage.Save();
|
|
796
|
+
this.messageSent.emit(userMessage);
|
|
797
|
+
// Look up the agent to get its ID
|
|
798
|
+
const agent = AIEngineBase.Instance.Agents.find(a => a.Name === agentName);
|
|
799
|
+
// Create AI response message BEFORE invoking agent (for duration tracking)
|
|
800
|
+
const md = new Metadata();
|
|
801
|
+
const agentResponseMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
802
|
+
agentResponseMessage.ConversationID = conversationId;
|
|
803
|
+
agentResponseMessage.Role = 'AI';
|
|
804
|
+
agentResponseMessage.Message = '⏳ Starting...'; // Initial message
|
|
805
|
+
agentResponseMessage.ParentID = userMessage.ID;
|
|
806
|
+
agentResponseMessage.Status = 'In-Progress';
|
|
807
|
+
agentResponseMessage.HiddenToUser = false;
|
|
808
|
+
// Set AgentID immediately for proper attribution
|
|
809
|
+
if (agent?.ID) {
|
|
810
|
+
agentResponseMessage.AgentID = agent.ID;
|
|
811
|
+
}
|
|
812
|
+
// Save the record to establish __mj_CreatedAt timestamp
|
|
813
|
+
await agentResponseMessage.Save();
|
|
814
|
+
this.messageSent.emit(agentResponseMessage);
|
|
815
|
+
// Invoke the agent directly
|
|
816
|
+
const result = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.conversationHistory, `User mentioned agent directly with @${agentName}`, agentResponseMessage.ID, undefined, // no payload for direct mention
|
|
817
|
+
this.createProgressCallback(agentResponseMessage.ID, agentName));
|
|
818
|
+
// Remove from active tasks
|
|
819
|
+
this.activeTasks.remove(taskId);
|
|
820
|
+
if (result && result.success) {
|
|
821
|
+
// Update the response message with agent result
|
|
822
|
+
agentResponseMessage.Message = result.agentRun?.Message || `✅ **${agentName}** completed`;
|
|
823
|
+
agentResponseMessage.Status = 'Complete';
|
|
824
|
+
if (result.agentRun.AgentID) {
|
|
825
|
+
agentResponseMessage.AgentID = result.agentRun.AgentID;
|
|
826
|
+
}
|
|
827
|
+
if (result.agentRun.ID) {
|
|
828
|
+
agentResponseMessage.AgentRunID = result.agentRun.ID;
|
|
829
|
+
}
|
|
830
|
+
// Save updates - this sets __mj_UpdatedAt for duration calculation
|
|
831
|
+
await agentResponseMessage.Save();
|
|
832
|
+
this.messageSent.emit(agentResponseMessage);
|
|
833
|
+
// Handle artifacts
|
|
834
|
+
if (result.payload && Object.keys(result.payload).length > 0) {
|
|
835
|
+
await this.createArtifactFromPayload(result.payload, agentResponseMessage, result.agentRun.AgentID);
|
|
836
|
+
this.messageSent.emit(agentResponseMessage);
|
|
837
|
+
}
|
|
838
|
+
// Mark user message as complete
|
|
839
|
+
userMessage.Status = 'Complete';
|
|
840
|
+
await userMessage.Save();
|
|
841
|
+
this.messageSent.emit(userMessage);
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
// Agent failed - create error message
|
|
845
|
+
const md = new Metadata();
|
|
846
|
+
const errorMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
847
|
+
errorMessage.ConversationID = conversationId;
|
|
848
|
+
errorMessage.Role = 'AI';
|
|
849
|
+
errorMessage.Message = `❌ **@${agentName}** failed\n\n${result?.agentRun?.ErrorMessage || 'Unknown error'}`;
|
|
850
|
+
errorMessage.ParentID = userMessage.ID;
|
|
851
|
+
errorMessage.Status = 'Error';
|
|
852
|
+
errorMessage.Error = result?.agentRun?.ErrorMessage || null;
|
|
853
|
+
errorMessage.HiddenToUser = false;
|
|
854
|
+
await errorMessage.Save();
|
|
855
|
+
this.messageSent.emit(errorMessage);
|
|
856
|
+
userMessage.Status = 'Complete';
|
|
857
|
+
await userMessage.Save();
|
|
858
|
+
this.messageSent.emit(userMessage);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
catch (error) {
|
|
862
|
+
console.error(`❌ Error invoking mentioned agent ${agentName}:`, error);
|
|
863
|
+
this.activeTasks.remove(taskId);
|
|
864
|
+
const md = new Metadata();
|
|
865
|
+
const errorMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
866
|
+
errorMessage.ConversationID = conversationId;
|
|
867
|
+
errorMessage.Role = 'AI';
|
|
868
|
+
errorMessage.Message = `❌ **@${agentName}** encountered an error\n\n${String(error)}`;
|
|
869
|
+
errorMessage.ParentID = userMessage.ID;
|
|
870
|
+
errorMessage.Status = 'Error';
|
|
871
|
+
errorMessage.Error = String(error);
|
|
872
|
+
errorMessage.HiddenToUser = false;
|
|
873
|
+
await errorMessage.Save();
|
|
874
|
+
this.messageSent.emit(errorMessage);
|
|
875
|
+
userMessage.Status = 'Complete';
|
|
876
|
+
await userMessage.Save();
|
|
877
|
+
this.messageSent.emit(userMessage);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Continue with the same agent from previous message (implicit continuation)
|
|
882
|
+
* Bypasses Conversation Manager - no status messages
|
|
883
|
+
*/
|
|
884
|
+
async continueWithAgent(userMessage, agentId, conversationId) {
|
|
885
|
+
// Load the agent entity to get its name
|
|
886
|
+
const md = new Metadata();
|
|
887
|
+
const rv = new RunView();
|
|
888
|
+
const agentResult = await rv.RunView({
|
|
889
|
+
EntityName: 'AI Agents',
|
|
890
|
+
ExtraFilter: `ID='${agentId}'`,
|
|
891
|
+
ResultType: 'entity_object'
|
|
892
|
+
}, this.currentUser);
|
|
893
|
+
if (!agentResult.Success || !agentResult.Results || agentResult.Results.length === 0) {
|
|
894
|
+
console.warn('⚠️ Could not load agent for continuation - falling back to Conversation Manager');
|
|
895
|
+
await this.processMessageThroughAgent(userMessage, { mentions: [], agentMention: null, userMentions: [] });
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
const agent = agentResult.Results[0];
|
|
899
|
+
const agentName = agent.Name || 'Agent';
|
|
900
|
+
// Add agent to active tasks
|
|
901
|
+
const taskId = this.activeTasks.add({
|
|
902
|
+
agentName: agentName,
|
|
903
|
+
status: 'Processing...',
|
|
904
|
+
relatedMessageId: userMessage.ID,
|
|
905
|
+
conversationDetailId: userMessage.ID
|
|
906
|
+
});
|
|
907
|
+
try {
|
|
908
|
+
// Update user message status to In-Progress
|
|
909
|
+
userMessage.Status = 'In-Progress';
|
|
910
|
+
await userMessage.Save();
|
|
911
|
+
this.messageSent.emit(userMessage);
|
|
912
|
+
// Create AI response message BEFORE invoking agent (for duration tracking)
|
|
913
|
+
const agentResponseMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
914
|
+
agentResponseMessage.ConversationID = conversationId;
|
|
915
|
+
agentResponseMessage.Role = 'AI';
|
|
916
|
+
agentResponseMessage.Message = '⏳ Starting...'; // Initial message
|
|
917
|
+
agentResponseMessage.ParentID = userMessage.ID;
|
|
918
|
+
agentResponseMessage.Status = 'In-Progress';
|
|
919
|
+
agentResponseMessage.HiddenToUser = false;
|
|
920
|
+
agentResponseMessage.AgentID = agentId;
|
|
921
|
+
// Save the record to establish __mj_CreatedAt timestamp
|
|
922
|
+
await agentResponseMessage.Save();
|
|
923
|
+
this.messageSent.emit(agentResponseMessage);
|
|
924
|
+
// Invoke the agent directly (continuation)
|
|
925
|
+
const result = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.conversationHistory, 'Continuing previous conversation with user', agentResponseMessage.ID, undefined, // no payload for continuation
|
|
926
|
+
this.createProgressCallback(agentResponseMessage.ID, agentName));
|
|
927
|
+
// Remove from active tasks
|
|
928
|
+
this.activeTasks.remove(taskId);
|
|
929
|
+
if (result && result.success) {
|
|
930
|
+
// Update the response message with agent result
|
|
931
|
+
agentResponseMessage.Message = result.agentRun?.Message || `✅ **${agentName}** completed`;
|
|
932
|
+
agentResponseMessage.Status = 'Complete';
|
|
933
|
+
if (result.agentRun.ID) {
|
|
934
|
+
agentResponseMessage.AgentRunID = result.agentRun.ID;
|
|
935
|
+
}
|
|
936
|
+
// Save updates - this sets __mj_UpdatedAt for duration calculation
|
|
937
|
+
await agentResponseMessage.Save();
|
|
938
|
+
this.messageSent.emit(agentResponseMessage);
|
|
939
|
+
// Handle artifacts
|
|
940
|
+
if (result.payload && Object.keys(result.payload).length > 0) {
|
|
941
|
+
await this.createArtifactFromPayload(result.payload, agentResponseMessage, agentId);
|
|
942
|
+
this.messageSent.emit(agentResponseMessage);
|
|
943
|
+
}
|
|
944
|
+
// Mark user message as complete
|
|
945
|
+
userMessage.Status = 'Complete';
|
|
946
|
+
await userMessage.Save();
|
|
947
|
+
this.messageSent.emit(userMessage);
|
|
948
|
+
}
|
|
949
|
+
else {
|
|
950
|
+
// Agent failed - create error message
|
|
951
|
+
const errorMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
952
|
+
errorMessage.ConversationID = conversationId;
|
|
953
|
+
errorMessage.Role = 'AI';
|
|
954
|
+
errorMessage.Message = `❌ **${agentName}** failed\n\n${result?.agentRun?.ErrorMessage || 'Unknown error'}`;
|
|
955
|
+
errorMessage.ParentID = userMessage.ID;
|
|
956
|
+
errorMessage.Status = 'Error';
|
|
957
|
+
errorMessage.Error = result?.agentRun?.ErrorMessage || null;
|
|
958
|
+
errorMessage.HiddenToUser = false;
|
|
959
|
+
await errorMessage.Save();
|
|
960
|
+
this.messageSent.emit(errorMessage);
|
|
961
|
+
userMessage.Status = 'Complete';
|
|
962
|
+
await userMessage.Save();
|
|
963
|
+
this.messageSent.emit(userMessage);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
catch (error) {
|
|
967
|
+
console.error(`❌ Error continuing with agent ${agentName}:`, error);
|
|
968
|
+
this.activeTasks.remove(taskId);
|
|
969
|
+
const errorMessage = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
970
|
+
errorMessage.ConversationID = conversationId;
|
|
971
|
+
errorMessage.Role = 'AI';
|
|
972
|
+
errorMessage.Message = `❌ **${agentName}** encountered an error\n\n${String(error)}`;
|
|
973
|
+
errorMessage.ParentID = userMessage.ID;
|
|
974
|
+
errorMessage.Status = 'Error';
|
|
975
|
+
errorMessage.Error = String(error);
|
|
976
|
+
errorMessage.HiddenToUser = false;
|
|
977
|
+
await errorMessage.Save();
|
|
978
|
+
this.messageSent.emit(errorMessage);
|
|
979
|
+
userMessage.Status = 'Complete';
|
|
980
|
+
await userMessage.Save();
|
|
981
|
+
this.messageSent.emit(userMessage);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Creates an artifact from an agent's payload and links it to the conversation detail
|
|
986
|
+
* @param payload The agent's payload object
|
|
987
|
+
* @param message The conversation detail message to link to
|
|
988
|
+
* @param agentId The ID of the agent that produced the payload
|
|
989
|
+
*/
|
|
990
|
+
async createArtifactFromPayload(payload, message, agentId) {
|
|
991
|
+
try {
|
|
992
|
+
const md = new Metadata();
|
|
993
|
+
// Create Artifact header
|
|
994
|
+
const artifact = await md.GetEntityObject('MJ: Artifacts', this.currentUser);
|
|
995
|
+
// Generate artifact name based on agent name and timestamp
|
|
996
|
+
const agentName = agentId
|
|
997
|
+
? AIEngineBase.Instance?.Agents?.find(a => a.ID === agentId)?.Name || 'Agent'
|
|
998
|
+
: 'Agent';
|
|
999
|
+
artifact.Name = `${agentName} Payload - ${new Date().toLocaleString()}`;
|
|
1000
|
+
artifact.Description = `Payload returned by ${agentName}`;
|
|
1001
|
+
// Use JSON artifact type (hardcoded ID from migration)
|
|
1002
|
+
artifact.TypeID = 'ae674c7e-ea0d-49ea-89e4-0649f5eb20d4'; // JSON type
|
|
1003
|
+
artifact.UserID = this.currentUser.ID;
|
|
1004
|
+
artifact.EnvironmentID = this.currentUser.EnvironmentID || 'F51358F3-9447-4176-B313-BF8025FD8D09';
|
|
1005
|
+
const artifactSaved = await artifact.Save();
|
|
1006
|
+
if (!artifactSaved) {
|
|
1007
|
+
console.error('Failed to save artifact');
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
// Create Artifact Version with content
|
|
1011
|
+
const version = await md.GetEntityObject('MJ: Artifact Versions', this.currentUser);
|
|
1012
|
+
version.ArtifactID = artifact.ID;
|
|
1013
|
+
version.VersionNumber = 1;
|
|
1014
|
+
version.Content = JSON.stringify(payload, null, 2);
|
|
1015
|
+
version.UserID = this.currentUser.ID;
|
|
1016
|
+
const versionSaved = await version.Save();
|
|
1017
|
+
if (!versionSaved) {
|
|
1018
|
+
console.error('Failed to save artifact version');
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
// Create M2M relationship using ConversationDetailArtifact junction table
|
|
1022
|
+
const junction = await md.GetEntityObject('MJ: Conversation Detail Artifacts', this.currentUser);
|
|
1023
|
+
junction.ConversationDetailID = message.ID;
|
|
1024
|
+
junction.ArtifactVersionID = version.ID;
|
|
1025
|
+
junction.Direction = 'Output'; // This artifact was produced as output from the agent
|
|
1026
|
+
const junctionSaved = await junction.Save();
|
|
1027
|
+
if (!junctionSaved) {
|
|
1028
|
+
console.error('Failed to create artifact-message association');
|
|
1029
|
+
}
|
|
1030
|
+
this.artifactCreated.emit({ artifactId: artifact.ID, versionId: version.ID, conversationDetailId: message.ID, name: artifact.Name });
|
|
1031
|
+
}
|
|
1032
|
+
catch (error) {
|
|
1033
|
+
console.error('Error creating artifact from payload:', error);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Name the conversation based on the first message using GraphQL AI client
|
|
1038
|
+
*/
|
|
1039
|
+
async nameConversation(message) {
|
|
1040
|
+
try {
|
|
1041
|
+
console.log('🏷️ Naming conversation based on first message...');
|
|
1042
|
+
// Load the Name Conversation prompt to get its ID
|
|
1043
|
+
await AIEngineBase.Instance.Config(false);
|
|
1044
|
+
const p = AIEngineBase.Instance.Prompts.find(pr => pr.Name === 'Name Conversation');
|
|
1045
|
+
if (!p) {
|
|
1046
|
+
console.warn('⚠️ Name Conversation prompt not found');
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
const promptId = p.ID;
|
|
1050
|
+
// Use GraphQL AI client to run the prompt (same client as agent)
|
|
1051
|
+
const provider = Metadata.Provider;
|
|
1052
|
+
if (!provider) {
|
|
1053
|
+
console.warn('⚠️ GraphQLDataProvider not available');
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
const aiClient = new GraphQLAIClient(provider);
|
|
1057
|
+
const result = await aiClient.RunAIPrompt({
|
|
1058
|
+
promptId: promptId,
|
|
1059
|
+
messages: [{ role: 'user', content: message }],
|
|
1060
|
+
});
|
|
1061
|
+
if (result && result.success && (result.parsedResult || result.output)) {
|
|
1062
|
+
// Use parsedResult if available, otherwise parse output
|
|
1063
|
+
const parsed = result.parsedResult ||
|
|
1064
|
+
(result.output ? JSON.parse(result.output) : null);
|
|
1065
|
+
if (parsed) {
|
|
1066
|
+
const { name, description } = parsed;
|
|
1067
|
+
if (name) {
|
|
1068
|
+
console.log('✅ Generated conversation name:', { name, description });
|
|
1069
|
+
// Update the conversation name and description in database AND state immediately
|
|
1070
|
+
await this.conversationState.saveConversation(this.conversationId, { Name: name, Description: description || '' }, this.currentUser);
|
|
1071
|
+
console.log('💾 Conversation name updated in database and UI');
|
|
1072
|
+
// Emit event for animation in conversation list
|
|
1073
|
+
this.conversationRenamed.emit({
|
|
1074
|
+
conversationId: this.conversationId,
|
|
1075
|
+
name: name,
|
|
1076
|
+
description: description || ''
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
else {
|
|
1082
|
+
console.warn('⚠️ Failed to generate conversation name');
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
catch (error) {
|
|
1086
|
+
console.error('❌ Error naming conversation:', error);
|
|
1087
|
+
// Don't show error to user - naming failures should be silent
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
static ɵfac = function MessageInputComponent_Factory(t) { return new (t || MessageInputComponent)(i0.ɵɵdirectiveInject(i1.DialogService), i0.ɵɵdirectiveInject(i2.ToastService), i0.ɵɵdirectiveInject(i3.ConversationAgentService), i0.ɵɵdirectiveInject(i4.ConversationStateService), i0.ɵɵdirectiveInject(i5.ActiveTasksService), i0.ɵɵdirectiveInject(i6.MentionAutocompleteService), i0.ɵɵdirectiveInject(i7.MentionParserService)); };
|
|
1091
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MessageInputComponent, selectors: [["mj-message-input"]], viewQuery: function MessageInputComponent_Query(rf, ctx) { if (rf & 1) {
|
|
1092
|
+
i0.ɵɵviewQuery(_c0, 5);
|
|
1093
|
+
} if (rf & 2) {
|
|
1094
|
+
let _t;
|
|
1095
|
+
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.messageTextarea = _t.first);
|
|
1096
|
+
} }, inputs: { conversationId: "conversationId", currentUser: "currentUser", disabled: "disabled", placeholder: "placeholder", parentMessageId: "parentMessageId", conversationHistory: "conversationHistory" }, outputs: { messageSent: "messageSent", agentResponse: "agentResponse", agentRunDetected: "agentRunDetected", artifactCreated: "artifactCreated", conversationRenamed: "conversationRenamed" }, decls: 11, vars: 11, consts: [["messageTextarea", ""], [1, "message-input-container"], ["rows", "3", 1, "message-input", 3, "ngModelChange", "keydown", "input", "ngModel", "placeholder", "disabled"], [3, "suggestionSelected", "closed", "suggestions", "position", "visible", "showAbove"], [1, "input-actions"], ["class", "processing-indicator", 4, "ngIf"], ["title", "Attach file (coming soon)", 1, "btn-attach", 3, "disabled"], [1, "fas", "fa-paperclip"], [1, "btn-send", 3, "click", "disabled", "title"], [1, "fas", "fa-paper-plane"], [1, "processing-indicator"], [1, "fas", "fa-circle-notch", "fa-spin"]], template: function MessageInputComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1097
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
1098
|
+
i0.ɵɵelementStart(0, "div", 1)(1, "textarea", 2, 0);
|
|
1099
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MessageInputComponent_Template_textarea_ngModelChange_1_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.messageText, $event) || (ctx.messageText = $event); return i0.ɵɵresetView($event); });
|
|
1100
|
+
i0.ɵɵlistener("keydown", function MessageInputComponent_Template_textarea_keydown_1_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onKeyDown($event)); })("input", function MessageInputComponent_Template_textarea_input_1_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onInput($event)); });
|
|
1101
|
+
i0.ɵɵtext(3, " ");
|
|
1102
|
+
i0.ɵɵelementEnd();
|
|
1103
|
+
i0.ɵɵelementStart(4, "mj-mention-dropdown", 3);
|
|
1104
|
+
i0.ɵɵlistener("suggestionSelected", function MessageInputComponent_Template_mj_mention_dropdown_suggestionSelected_4_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onMentionSelected($event)); })("closed", function MessageInputComponent_Template_mj_mention_dropdown_closed_4_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.closeMentionDropdown()); });
|
|
1105
|
+
i0.ɵɵelementEnd();
|
|
1106
|
+
i0.ɵɵelementStart(5, "div", 4);
|
|
1107
|
+
i0.ɵɵtemplate(6, MessageInputComponent_div_6_Template, 4, 0, "div", 5);
|
|
1108
|
+
i0.ɵɵelementStart(7, "button", 6);
|
|
1109
|
+
i0.ɵɵelement(8, "i", 7);
|
|
1110
|
+
i0.ɵɵelementEnd();
|
|
1111
|
+
i0.ɵɵelementStart(9, "button", 8);
|
|
1112
|
+
i0.ɵɵlistener("click", function MessageInputComponent_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSend()); });
|
|
1113
|
+
i0.ɵɵelement(10, "i", 9);
|
|
1114
|
+
i0.ɵɵelementEnd()()();
|
|
1115
|
+
} if (rf & 2) {
|
|
1116
|
+
i0.ɵɵadvance();
|
|
1117
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.messageText);
|
|
1118
|
+
i0.ɵɵproperty("placeholder", ctx.placeholder)("disabled", ctx.disabled || ctx.isSending);
|
|
1119
|
+
i0.ɵɵadvance(3);
|
|
1120
|
+
i0.ɵɵproperty("suggestions", ctx.mentionSuggestions)("position", ctx.mentionDropdownPosition)("visible", ctx.showMentionDropdown)("showAbove", ctx.mentionDropdownShowAbove);
|
|
1121
|
+
i0.ɵɵadvance(2);
|
|
1122
|
+
i0.ɵɵproperty("ngIf", ctx.isProcessing);
|
|
1123
|
+
i0.ɵɵadvance();
|
|
1124
|
+
i0.ɵɵproperty("disabled", ctx.disabled);
|
|
1125
|
+
i0.ɵɵadvance(2);
|
|
1126
|
+
i0.ɵɵproperty("disabled", !ctx.canSend)("title", ctx.isSending ? "Sending..." : "Send message");
|
|
1127
|
+
} }, dependencies: [i8.NgIf, i9.DefaultValueAccessor, i9.NgControlStatus, i9.NgModel, i10.MentionDropdownComponent], styles: [".message-input-container[_ngcontent-%COMP%] {\n position: relative;\n padding: 16px 24px;\n border-top: 1px solid #D9D9D9;\n background: #FFF;\n}\n\n.message-input-wrapper[_ngcontent-%COMP%] {\n border: 2px solid #D9D9D9;\n border-radius: 8px;\n padding: 12px;\n transition: border-color 0.2s, box-shadow 0.2s;\n background: #FFF;\n}\n\n.message-input-wrapper[_ngcontent-%COMP%]:focus-within {\n border-color: #0076B6;\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.1);\n}\n\n.message-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0;\n border: none;\n resize: none;\n font-family: inherit;\n font-size: 14px;\n min-height: 40px;\n max-height: 200px;\n line-height: 1.5;\n}\n\n.message-input[_ngcontent-%COMP%]:focus {\n outline: none;\n}\n\n.message-input[_ngcontent-%COMP%]:disabled {\n background: #F4F4F4;\n cursor: not-allowed;\n}\n.input-actions[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-top: 12px;\n}\n.btn-attach[_ngcontent-%COMP%] {\n padding: 8px 16px;\n background: transparent;\n border: 1px solid #D9D9D9;\n border-radius: 6px;\n cursor: pointer;\n color: #333;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.btn-attach[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #F4F4F4;\n border-color: #AAA;\n}\n.btn-attach[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-send[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n background: #3B82F6;\n color: white;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n flex-shrink: 0;\n}\n.btn-send[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #2563EB;\n}\n.btn-send[_ngcontent-%COMP%]:disabled {\n background: #D9D9D9;\n color: #AAA;\n cursor: not-allowed;\n}\n.btn-send[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n.processing-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #6B7280;\n margin-right: auto;\n}\n.processing-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #0076B6;\n}"] });
|
|
1128
|
+
}
|
|
1129
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MessageInputComponent, [{
|
|
1130
|
+
type: Component,
|
|
1131
|
+
args: [{ selector: 'mj-message-input', template: "<div class=\"message-input-container\">\n <textarea\n #messageTextarea\n class=\"message-input\"\n [(ngModel)]=\"messageText\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled || isSending\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n rows=\"3\">\n </textarea>\n\n <!-- Mention Autocomplete Dropdown -->\n <mj-mention-dropdown\n [suggestions]=\"mentionSuggestions\"\n [position]=\"mentionDropdownPosition\"\n [visible]=\"showMentionDropdown\"\n [showAbove]=\"mentionDropdownShowAbove\"\n (suggestionSelected)=\"onMentionSelected($event)\"\n (closed)=\"closeMentionDropdown()\">\n </mj-mention-dropdown>\n\n <div class=\"input-actions\">\n <div class=\"processing-indicator\" *ngIf=\"isProcessing\">\n <i class=\"fas fa-circle-notch fa-spin\"></i>\n <span>AI is responding...</span>\n </div>\n <button\n class=\"btn-attach\"\n [disabled]=\"disabled\"\n title=\"Attach file (coming soon)\">\n <i class=\"fas fa-paperclip\"></i>\n </button>\n <button\n class=\"btn-send\"\n [disabled]=\"!canSend\"\n (click)=\"onSend()\"\n [title]=\"isSending ? 'Sending...' : 'Send message'\">\n <i class=\"fas fa-paper-plane\"></i>\n </button>\n </div>\n</div>", styles: [".message-input-container {\n position: relative;\n padding: 16px 24px;\n border-top: 1px solid #D9D9D9;\n background: #FFF;\n}\n\n.message-input-wrapper {\n border: 2px solid #D9D9D9;\n border-radius: 8px;\n padding: 12px;\n transition: border-color 0.2s, box-shadow 0.2s;\n background: #FFF;\n}\n\n.message-input-wrapper:focus-within {\n border-color: #0076B6;\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.1);\n}\n\n.message-input {\n width: 100%;\n padding: 0;\n border: none;\n resize: none;\n font-family: inherit;\n font-size: 14px;\n min-height: 40px;\n max-height: 200px;\n line-height: 1.5;\n}\n\n.message-input:focus {\n outline: none;\n}\n\n.message-input:disabled {\n background: #F4F4F4;\n cursor: not-allowed;\n}\n.input-actions {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-top: 12px;\n}\n.btn-attach {\n padding: 8px 16px;\n background: transparent;\n border: 1px solid #D9D9D9;\n border-radius: 6px;\n cursor: pointer;\n color: #333;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.btn-attach:hover:not(:disabled) {\n background: #F4F4F4;\n border-color: #AAA;\n}\n.btn-attach:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-send {\n width: 40px;\n height: 40px;\n background: #3B82F6;\n color: white;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n flex-shrink: 0;\n}\n.btn-send:hover:not(:disabled) {\n background: #2563EB;\n}\n.btn-send:disabled {\n background: #D9D9D9;\n color: #AAA;\n cursor: not-allowed;\n}\n.btn-send i {\n font-size: 16px;\n}\n.processing-indicator {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #6B7280;\n margin-right: auto;\n}\n.processing-indicator i {\n color: #0076B6;\n}"] }]
|
|
1132
|
+
}], () => [{ type: i1.DialogService }, { type: i2.ToastService }, { type: i3.ConversationAgentService }, { type: i4.ConversationStateService }, { type: i5.ActiveTasksService }, { type: i6.MentionAutocompleteService }, { type: i7.MentionParserService }], { conversationId: [{
|
|
1133
|
+
type: Input
|
|
1134
|
+
}], currentUser: [{
|
|
1135
|
+
type: Input
|
|
1136
|
+
}], disabled: [{
|
|
1137
|
+
type: Input
|
|
1138
|
+
}], placeholder: [{
|
|
1139
|
+
type: Input
|
|
1140
|
+
}], parentMessageId: [{
|
|
1141
|
+
type: Input
|
|
1142
|
+
}], conversationHistory: [{
|
|
1143
|
+
type: Input
|
|
1144
|
+
}], messageSent: [{
|
|
1145
|
+
type: Output
|
|
1146
|
+
}], agentResponse: [{
|
|
1147
|
+
type: Output
|
|
1148
|
+
}], agentRunDetected: [{
|
|
1149
|
+
type: Output
|
|
1150
|
+
}], artifactCreated: [{
|
|
1151
|
+
type: Output
|
|
1152
|
+
}], conversationRenamed: [{
|
|
1153
|
+
type: Output
|
|
1154
|
+
}], messageTextarea: [{
|
|
1155
|
+
type: ViewChild,
|
|
1156
|
+
args: ['messageTextarea']
|
|
1157
|
+
}] }); })();
|
|
1158
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MessageInputComponent, { className: "MessageInputComponent", filePath: "src/lib/components/message/message-input.component.ts", lineNumber: 21 }); })();
|
|
1159
|
+
//# sourceMappingURL=message-input.component.js.map
|