@memberjunction/ng-conversations 2.112.0 → 2.113.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.
Files changed (205) hide show
  1. package/dist/lib/components/agent/active-agent-indicator.component.d.ts +1 -1
  2. package/dist/lib/components/agent/active-agent-indicator.component.d.ts.map +1 -1
  3. package/dist/lib/components/agent/active-agent-indicator.component.js +13 -15
  4. package/dist/lib/components/agent/active-agent-indicator.component.js.map +1 -1
  5. package/dist/lib/components/agent/agent-process-panel.component.d.ts +1 -1
  6. package/dist/lib/components/agent/agent-process-panel.component.d.ts.map +1 -1
  7. package/dist/lib/components/agent/agent-process-panel.component.js +14 -18
  8. package/dist/lib/components/agent/agent-process-panel.component.js.map +1 -1
  9. package/dist/lib/components/artifact/artifact-share-modal.component.d.ts +1 -1
  10. package/dist/lib/components/artifact/artifact-share-modal.component.d.ts.map +1 -1
  11. package/dist/lib/components/artifact/artifact-share-modal.component.js +11 -11
  12. package/dist/lib/components/artifact/artifact-share-modal.component.js.map +1 -1
  13. package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts +1 -1
  14. package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts.map +1 -1
  15. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js +30 -24
  16. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js.map +1 -1
  17. package/dist/lib/components/collection/artifact-create-modal.component.d.ts +1 -1
  18. package/dist/lib/components/collection/artifact-create-modal.component.d.ts.map +1 -1
  19. package/dist/lib/components/collection/artifact-create-modal.component.js +10 -8
  20. package/dist/lib/components/collection/artifact-create-modal.component.js.map +1 -1
  21. package/dist/lib/components/collection/collection-artifact-card.component.d.ts +9 -8
  22. package/dist/lib/components/collection/collection-artifact-card.component.d.ts.map +1 -1
  23. package/dist/lib/components/collection/collection-artifact-card.component.js +51 -35
  24. package/dist/lib/components/collection/collection-artifact-card.component.js.map +1 -1
  25. package/dist/lib/components/collection/collection-form-modal.component.d.ts +1 -1
  26. package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
  27. package/dist/lib/components/collection/collection-form-modal.component.js +6 -5
  28. package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
  29. package/dist/lib/components/collection/collection-share-modal.component.d.ts +1 -1
  30. package/dist/lib/components/collection/collection-share-modal.component.d.ts.map +1 -1
  31. package/dist/lib/components/collection/collection-share-modal.component.js +12 -12
  32. package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
  33. package/dist/lib/components/collection/collection-tree.component.d.ts +1 -1
  34. package/dist/lib/components/collection/collection-tree.component.d.ts.map +1 -1
  35. package/dist/lib/components/collection/collection-tree.component.js +11 -11
  36. package/dist/lib/components/collection/collection-tree.component.js.map +1 -1
  37. package/dist/lib/components/collection/collection-view.component.d.ts +29 -10
  38. package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
  39. package/dist/lib/components/collection/collection-view.component.js +128 -62
  40. package/dist/lib/components/collection/collection-view.component.js.map +1 -1
  41. package/dist/lib/components/collection/collections-full-view.component.d.ts +19 -7
  42. package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
  43. package/dist/lib/components/collection/collections-full-view.component.js +99 -69
  44. package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
  45. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +38 -1
  46. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  47. package/dist/lib/components/conversation/conversation-chat-area.component.js +303 -181
  48. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  49. package/dist/lib/components/conversation/conversation-empty-state.component.d.ts +1 -1
  50. package/dist/lib/components/conversation/conversation-empty-state.component.d.ts.map +1 -1
  51. package/dist/lib/components/conversation/conversation-empty-state.component.js +21 -21
  52. package/dist/lib/components/conversation/conversation-empty-state.component.js.map +1 -1
  53. package/dist/lib/components/conversation/conversation-list.component.d.ts +11 -4
  54. package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
  55. package/dist/lib/components/conversation/conversation-list.component.js +122 -81
  56. package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
  57. package/dist/lib/components/export/export-modal.component.d.ts +1 -1
  58. package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
  59. package/dist/lib/components/export/export-modal.component.js +11 -9
  60. package/dist/lib/components/export/export-modal.component.js.map +1 -1
  61. package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts +25 -0
  62. package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts.map +1 -0
  63. package/dist/lib/components/global-tasks/global-tasks-panel.component.js +206 -0
  64. package/dist/lib/components/global-tasks/global-tasks-panel.component.js.map +1 -0
  65. package/dist/lib/components/library/library-full-view.component.d.ts +1 -1
  66. package/dist/lib/components/library/library-full-view.component.d.ts.map +1 -1
  67. package/dist/lib/components/library/library-full-view.component.js +6 -5
  68. package/dist/lib/components/library/library-full-view.component.js.map +1 -1
  69. package/dist/lib/components/members/members-modal.component.d.ts +1 -1
  70. package/dist/lib/components/members/members-modal.component.d.ts.map +1 -1
  71. package/dist/lib/components/members/members-modal.component.js +8 -8
  72. package/dist/lib/components/members/members-modal.component.js.map +1 -1
  73. package/dist/lib/components/message/conversation-message-rating.component.d.ts +47 -0
  74. package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -0
  75. package/dist/lib/components/message/conversation-message-rating.component.js +224 -0
  76. package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -0
  77. package/dist/lib/components/message/message-input-box.component.d.ts +1 -1
  78. package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
  79. package/dist/lib/components/message/message-input-box.component.js +4 -14
  80. package/dist/lib/components/message/message-input-box.component.js.map +1 -1
  81. package/dist/lib/components/message/message-input.component.d.ts +18 -3
  82. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  83. package/dist/lib/components/message/message-input.component.js +288 -297
  84. package/dist/lib/components/message/message-input.component.js.map +1 -1
  85. package/dist/lib/components/message/message-item.component.d.ts +32 -2
  86. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  87. package/dist/lib/components/message/message-item.component.js +253 -129
  88. package/dist/lib/components/message/message-item.component.js.map +1 -1
  89. package/dist/lib/components/message/message-list.component.d.ts +4 -2
  90. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  91. package/dist/lib/components/message/message-list.component.js +35 -18
  92. package/dist/lib/components/message/message-list.component.js.map +1 -1
  93. package/dist/lib/components/navigation/conversation-navigation.component.d.ts +7 -1
  94. package/dist/lib/components/navigation/conversation-navigation.component.d.ts.map +1 -1
  95. package/dist/lib/components/navigation/conversation-navigation.component.js +24 -14
  96. package/dist/lib/components/navigation/conversation-navigation.component.js.map +1 -1
  97. package/dist/lib/components/project/project-form-modal.component.d.ts +1 -1
  98. package/dist/lib/components/project/project-form-modal.component.d.ts.map +1 -1
  99. package/dist/lib/components/project/project-form-modal.component.js +7 -7
  100. package/dist/lib/components/project/project-form-modal.component.js.map +1 -1
  101. package/dist/lib/components/project/project-selector.component.d.ts +1 -1
  102. package/dist/lib/components/project/project-selector.component.d.ts.map +1 -1
  103. package/dist/lib/components/project/project-selector.component.js +10 -10
  104. package/dist/lib/components/project/project-selector.component.js.map +1 -1
  105. package/dist/lib/components/search/search-panel.component.d.ts +1 -1
  106. package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
  107. package/dist/lib/components/search/search-panel.component.js +16 -8
  108. package/dist/lib/components/search/search-panel.component.js.map +1 -1
  109. package/dist/lib/components/share/share-modal.component.d.ts +1 -1
  110. package/dist/lib/components/share/share-modal.component.d.ts.map +1 -1
  111. package/dist/lib/components/share/share-modal.component.js +12 -12
  112. package/dist/lib/components/share/share-modal.component.js.map +1 -1
  113. package/dist/lib/components/shared/user-picker.component.d.ts +1 -1
  114. package/dist/lib/components/shared/user-picker.component.d.ts.map +1 -1
  115. package/dist/lib/components/shared/user-picker.component.js +7 -7
  116. package/dist/lib/components/shared/user-picker.component.js.map +1 -1
  117. package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts +1 -1
  118. package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts.map +1 -1
  119. package/dist/lib/components/sidebar/conversation-sidebar.component.js +1 -1
  120. package/dist/lib/components/sidebar/conversation-sidebar.component.js.map +1 -1
  121. package/dist/lib/components/task/tasks-full-view.component.d.ts +1 -1
  122. package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
  123. package/dist/lib/components/task/tasks-full-view.component.js +20 -18
  124. package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
  125. package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +18 -29
  126. package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -1
  127. package/dist/lib/components/tasks/tasks-dropdown.component.js +178 -218
  128. package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
  129. package/dist/lib/components/thread/thread-panel.component.d.ts +1 -1
  130. package/dist/lib/components/thread/thread-panel.component.d.ts.map +1 -1
  131. package/dist/lib/components/thread/thread-panel.component.js +2 -2
  132. package/dist/lib/components/thread/thread-panel.component.js.map +1 -1
  133. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +15 -9
  134. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  135. package/dist/lib/components/workspace/conversation-workspace.component.js +126 -79
  136. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  137. package/dist/lib/conversations.module.d.ts +54 -52
  138. package/dist/lib/conversations.module.d.ts.map +1 -1
  139. package/dist/lib/conversations.module.js +11 -3
  140. package/dist/lib/conversations.module.js.map +1 -1
  141. package/dist/lib/models/conversation-complete-query.model.d.ts +31 -22
  142. package/dist/lib/models/conversation-complete-query.model.d.ts.map +1 -1
  143. package/dist/lib/models/conversation-complete-query.model.js +5 -2
  144. package/dist/lib/models/conversation-complete-query.model.js.map +1 -1
  145. package/dist/lib/models/lazy-artifact-info.d.ts +4 -1
  146. package/dist/lib/models/lazy-artifact-info.d.ts.map +1 -1
  147. package/dist/lib/models/lazy-artifact-info.js +12 -4
  148. package/dist/lib/models/lazy-artifact-info.js.map +1 -1
  149. package/dist/lib/services/active-tasks.service.d.ts +18 -0
  150. package/dist/lib/services/active-tasks.service.d.ts.map +1 -1
  151. package/dist/lib/services/active-tasks.service.js +53 -3
  152. package/dist/lib/services/active-tasks.service.js.map +1 -1
  153. package/dist/lib/services/agent-state.service.d.ts +1 -1
  154. package/dist/lib/services/agent-state.service.d.ts.map +1 -1
  155. package/dist/lib/services/agent-state.service.js +11 -11
  156. package/dist/lib/services/agent-state.service.js.map +1 -1
  157. package/dist/lib/services/artifact-permission.service.d.ts +1 -1
  158. package/dist/lib/services/artifact-permission.service.d.ts.map +1 -1
  159. package/dist/lib/services/artifact-permission.service.js +15 -13
  160. package/dist/lib/services/artifact-permission.service.js.map +1 -1
  161. package/dist/lib/services/artifact-state.service.d.ts +23 -6
  162. package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
  163. package/dist/lib/services/artifact-state.service.js +129 -38
  164. package/dist/lib/services/artifact-state.service.js.map +1 -1
  165. package/dist/lib/services/artifact-use-tracking.service.d.ts +35 -0
  166. package/dist/lib/services/artifact-use-tracking.service.d.ts.map +1 -0
  167. package/dist/lib/services/artifact-use-tracking.service.js +76 -0
  168. package/dist/lib/services/artifact-use-tracking.service.js.map +1 -0
  169. package/dist/lib/services/collection-permission.service.d.ts +1 -1
  170. package/dist/lib/services/collection-permission.service.d.ts.map +1 -1
  171. package/dist/lib/services/collection-permission.service.js +13 -13
  172. package/dist/lib/services/collection-permission.service.js.map +1 -1
  173. package/dist/lib/services/conversation-agent.service.d.ts +30 -3
  174. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  175. package/dist/lib/services/conversation-agent.service.js +127 -34
  176. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  177. package/dist/lib/services/conversation-state.service.d.ts +14 -1
  178. package/dist/lib/services/conversation-state.service.d.ts.map +1 -1
  179. package/dist/lib/services/conversation-state.service.js +36 -9
  180. package/dist/lib/services/conversation-state.service.js.map +1 -1
  181. package/dist/lib/services/data-cache.service.d.ts +1 -1
  182. package/dist/lib/services/data-cache.service.d.ts.map +1 -1
  183. package/dist/lib/services/data-cache.service.js +13 -13
  184. package/dist/lib/services/data-cache.service.js.map +1 -1
  185. package/dist/lib/services/export.service.d.ts +1 -1
  186. package/dist/lib/services/export.service.d.ts.map +1 -1
  187. package/dist/lib/services/export.service.js +13 -15
  188. package/dist/lib/services/export.service.js.map +1 -1
  189. package/dist/lib/services/mention-autocomplete.service.d.ts +1 -1
  190. package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
  191. package/dist/lib/services/mention-autocomplete.service.js +5 -5
  192. package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
  193. package/dist/lib/services/mention-parser.service.d.ts +1 -1
  194. package/dist/lib/services/mention-parser.service.d.ts.map +1 -1
  195. package/dist/lib/services/mention-parser.service.js +16 -13
  196. package/dist/lib/services/mention-parser.service.js.map +1 -1
  197. package/dist/lib/services/search.service.d.ts +1 -1
  198. package/dist/lib/services/search.service.d.ts.map +1 -1
  199. package/dist/lib/services/search.service.js +32 -26
  200. package/dist/lib/services/search.service.js.map +1 -1
  201. package/dist/public-api.d.ts +3 -0
  202. package/dist/public-api.d.ts.map +1 -1
  203. package/dist/public-api.js +3 -0
  204. package/dist/public-api.js.map +1 -1
  205. package/package.json +14 -13
@@ -1,7 +1,8 @@
1
- import { Component, Input, Output, EventEmitter, ViewChild, } from '@angular/core';
2
- import { Metadata, RunView } from '@memberjunction/global';
1
+ import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
2
+ import { Metadata } from '@memberjunction/core';
3
3
  import { GraphQLDataProvider, GraphQLAIClient } from '@memberjunction/graphql-dataprovider';
4
4
  import { AIEngineBase } from '@memberjunction/ai-engine-base';
5
+ import { MJNotificationService } from '@memberjunction/ng-notifications';
5
6
  import * as i0 from "@angular/core";
6
7
  import * as i1 from "../../services/dialog.service";
7
8
  import * as i2 from "../../services/toast.service";
@@ -37,12 +38,16 @@ export class MessageInputComponent {
37
38
  // Default artifact type ID for JSON (when agent doesn't specify DefaultArtifactTypeID)
38
39
  JSON_ARTIFACT_TYPE_ID = 'ae674c7e-ea0d-49ea-89e4-0649f5eb20d4';
39
40
  conversationId;
41
+ conversationName; // For task tracking display
40
42
  currentUser;
41
43
  disabled = false;
42
44
  placeholder = 'Type a message... (Ctrl+Enter to send)';
43
45
  parentMessageId; // Optional: for replying in threads
44
46
  conversationHistory = []; // For agent context
45
47
  initialMessage = null; // Message to send automatically when component initializes
48
+ artifactsByDetailId; // Pre-loaded artifact data for performance
49
+ agentRunsByDetailId; // Pre-loaded agent run data for performance
50
+ inProgressMessageIds; // Message IDs that are in-progress and need streaming reconnection
46
51
  messageSent = new EventEmitter();
47
52
  agentResponse = new EventEmitter();
48
53
  agentRunDetected = new EventEmitter();
@@ -80,12 +85,18 @@ export class MessageInputComponent {
80
85
  await this.mentionAutocomplete.initialize(this.currentUser);
81
86
  // Subscribe to PubSub for task progress updates
82
87
  this.subscribeToPushStatus();
88
+ // Reconnect to any in-progress messages for streaming updates
89
+ this.reconnectInProgressMessages();
83
90
  }
84
91
  ngOnChanges(changes) {
85
92
  // When conversation changes, focus the input
86
93
  if (changes['conversationId'] && !changes['conversationId'].firstChange) {
87
94
  this.focusInput();
88
95
  }
96
+ // When in-progress message IDs change (switching conversations), reconnect
97
+ if (changes['inProgressMessageIds']) {
98
+ this.reconnectInProgressMessages();
99
+ }
89
100
  }
90
101
  ngAfterViewInit() {
91
102
  // Focus input on initial load
@@ -115,6 +126,24 @@ export class MessageInputComponent {
115
126
  }
116
127
  }, 100);
117
128
  }
129
+ /**
130
+ * Reconnect to in-progress messages for streaming updates
131
+ * This is called when:
132
+ * 1. Component initializes (ngOnInit)
133
+ * 2. Conversation changes (ngOnChanges)
134
+ * 3. User returns to a conversation with in-progress messages
135
+ */
136
+ reconnectInProgressMessages() {
137
+ if (!this.inProgressMessageIds || this.inProgressMessageIds.length === 0) {
138
+ return;
139
+ }
140
+ console.log(`🔌 Reconnecting to ${this.inProgressMessageIds.length} in-progress messages for streaming updates`);
141
+ // Register all in-progress message IDs to receive PubSub updates
142
+ for (const messageId of this.inProgressMessageIds) {
143
+ this.activeTaskExecutionMessageIds.add(messageId);
144
+ }
145
+ console.log(`✅ Registered ${this.activeTaskExecutionMessageIds.size} messages for streaming updates`);
146
+ }
118
147
  /**
119
148
  * Subscribe to PubSub for real-time task orchestration progress updates
120
149
  */
@@ -366,13 +395,18 @@ export class MessageInputComponent {
366
395
  */
367
396
  async handleAgentContinuity(messageDetail, lastAgentId, mentionResult, isFirstMessage) {
368
397
  console.log('🔍 Previous agent found, checking continuity intent...');
369
- const intent = await this.checkContinuityIntent(lastAgentId, messageDetail.Message);
370
- if (intent === 'YES') {
371
- console.log('✅ Intent check: YES - continuing with previous agent');
372
- await this.executeRouteWithNaming(() => this.continueWithAgent(messageDetail, lastAgentId, this.conversationId), messageDetail.Message, isFirstMessage);
398
+ const intentResult = await this.checkContinuityIntent(lastAgentId, messageDetail.Message);
399
+ if (intentResult.decision === 'YES') {
400
+ console.log('✅ Intent check: YES - continuing with previous agent', {
401
+ reasoning: intentResult.reasoning,
402
+ targetArtifactVersionId: intentResult.targetArtifactVersionId
403
+ });
404
+ await this.executeRouteWithNaming(() => this.continueWithAgent(messageDetail, lastAgentId, this.conversationId, intentResult.targetArtifactVersionId), messageDetail.Message, isFirstMessage);
373
405
  }
374
406
  else {
375
- console.log(`🤖 Intent check: ${intent} - routing through Sage for evaluation`);
407
+ console.log(`🤖 Intent check: ${intentResult.decision} - routing through Sage for evaluation`, {
408
+ reasoning: intentResult.reasoning
409
+ });
376
410
  await this.executeRouteWithNaming(() => this.processMessageThroughAgent(messageDetail, mentionResult), messageDetail.Message, isFirstMessage);
377
411
  }
378
412
  }
@@ -390,7 +424,9 @@ export class MessageInputComponent {
390
424
  const lastAIMessage = this.conversationHistory
391
425
  .slice()
392
426
  .reverse()
393
- .find((msg) => msg.Role === 'AI' && msg.AgentID && msg.AgentID !== this.converationManagerAgent?.ID);
427
+ .find(msg => msg.Role === 'AI' &&
428
+ msg.AgentID &&
429
+ msg.AgentID !== this.converationManagerAgent?.ID);
394
430
  return lastAIMessage?.AgentID || null;
395
431
  }
396
432
  /**
@@ -401,12 +437,20 @@ export class MessageInputComponent {
401
437
  // Emit event to show temporary "Analyzing intent..." message in conversation
402
438
  this.intentCheckStarted.emit();
403
439
  try {
404
- const intent = await this.agentService.checkAgentContinuityIntent(agentId, message, this.conversationHistory);
440
+ // Build context from pre-loaded maps (if available)
441
+ if (!this.artifactsByDetailId || !this.agentRunsByDetailId) {
442
+ console.warn('⚠️ Artifact/agent run context not available for intent check');
443
+ return { decision: 'UNSURE', reasoning: 'Context not available' };
444
+ }
445
+ const intent = await this.agentService.checkAgentContinuityIntent(agentId, message, this.conversationHistory, {
446
+ artifactsByDetailId: this.artifactsByDetailId,
447
+ agentRunsByDetailId: this.agentRunsByDetailId
448
+ });
405
449
  return intent;
406
450
  }
407
451
  catch (error) {
408
452
  console.error('❌ Intent check failed, defaulting to UNSURE:', error);
409
- return 'UNSURE';
453
+ return { decision: 'UNSURE', reasoning: 'Intent check failed with error' };
410
454
  }
411
455
  finally {
412
456
  // Emit event to remove temporary intent checking message
@@ -418,7 +462,10 @@ export class MessageInputComponent {
418
462
  */
419
463
  async executeRouteWithNaming(routeFunction, userMessage, isFirstMessage) {
420
464
  if (isFirstMessage) {
421
- await Promise.all([routeFunction(), this.nameConversation(userMessage)]);
465
+ await Promise.all([
466
+ routeFunction(),
467
+ this.nameConversation(userMessage)
468
+ ]);
422
469
  }
423
470
  else {
424
471
  await routeFunction();
@@ -476,12 +523,6 @@ export class MessageInputComponent {
476
523
  return async (progress) => {
477
524
  let progressAgentRun = progress.metadata?.agentRun;
478
525
  const progressAgentRunId = progressAgentRun?.ID || progress.metadata?.agentRunId;
479
- // if (!progressAgentRun && progressAgentRunId) {
480
- // // load the full agent run object from the database if we only have the ID
481
- // const md = new Metadata();
482
- // progressAgentRun = await md.GetEntityObject<AIAgentRunEntity>("MJ: AI Agent Runs");
483
- // await progressAgentRun.Load(progressAgentRunId);
484
- // }
485
526
  // Capture the agent run ID from the first progress message
486
527
  if (!capturedAgentRunId && progressAgentRunId) {
487
528
  capturedAgentRunId = progressAgentRunId;
@@ -514,7 +555,7 @@ export class MessageInputComponent {
514
555
  this.agentRunUpdate.emit({
515
556
  conversationDetailId: conversationDetail.ID,
516
557
  agentRun: progressAgentRun,
517
- agentRunId: progressAgentRunId,
558
+ agentRunId: progressAgentRunId
518
559
  });
519
560
  }
520
561
  else if (progressAgentRunId && !capturedAgentRunId) {
@@ -522,7 +563,7 @@ export class MessageInputComponent {
522
563
  // This will trigger a database query to load the agent run
523
564
  this.agentRunDetected.emit({
524
565
  conversationDetailId: conversationDetail.ID,
525
- agentRunId: progressAgentRunId,
566
+ agentRunId: progressAgentRunId
526
567
  });
527
568
  }
528
569
  if (conversationDetail.Status === 'In-Progress') {
@@ -541,7 +582,7 @@ export class MessageInputComponent {
541
582
  }
542
583
  console.log(`[${agentName}] Progress: ${progress.step} - ${progress.message} (${progress.percentage}%)`, {
543
584
  agentRunId: progressAgentRunId,
544
- conversationDetailId: conversationDetail.ID,
585
+ conversationDetailId: conversationDetail.ID
545
586
  });
546
587
  };
547
588
  }
@@ -577,24 +618,19 @@ export class MessageInputComponent {
577
618
  status: 'Evaluating message...',
578
619
  relatedMessageId: userMessage.ID,
579
620
  conversationDetailId: conversationManagerMessage.ID,
621
+ conversationId: this.conversationId,
622
+ conversationName: this.conversationName
580
623
  });
581
624
  const result = await this.agentService.processMessage(conversationId, userMessage, this.conversationHistory, conversationManagerMessage.ID, this.createProgressCallback(conversationManagerMessage, 'Sage'));
582
- // Remove Sage from active tasks
583
- if (taskId) {
584
- this.activeTasks.remove(taskId);
585
- taskId = null;
586
- }
625
+ // Task will be removed automatically in markMessageComplete()
626
+ // DO NOT remove here - agent may still be streaming/processing
627
+ taskId = null; // Clear reference but don't remove from service
587
628
  if (!result || !result.success) {
588
- // Evaluation failed - mark as complete to stop progress updates
589
- this.markMessageComplete(conversationManagerMessage);
590
- conversationManagerMessage.Status = 'Error';
591
- conversationManagerMessage.Message = `❌ Evaluation failed`;
592
- conversationManagerMessage.Error = result?.agentRun?.ErrorMessage || 'Agent evaluation failed';
593
- await conversationManagerMessage.Save();
594
- this.messageSent.emit(conversationManagerMessage);
595
- userMessage.Status = 'Complete';
596
- await userMessage.Save();
597
- this.messageSent.emit(userMessage);
629
+ // Evaluation failed - use updateConversationDetail to ensure task cleanup
630
+ const errorMsg = result?.agentRun?.ErrorMessage || 'Agent evaluation failed';
631
+ conversationManagerMessage.Error = errorMsg;
632
+ await this.updateConversationDetail(conversationManagerMessage, `❌ Evaluation failed`, 'Error');
633
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
598
634
  console.warn('⚠️ Sage failed:', result?.agentRun?.ErrorMessage);
599
635
  // Clean up completion timestamp
600
636
  this.cleanupCompletionTimestamp(conversationManagerMessage.ID);
@@ -606,7 +642,7 @@ export class MessageInputComponent {
606
642
  hasMessage: !!result.agentRun.Message,
607
643
  payloadKeys: result.payload ? Object.keys(result.payload) : [],
608
644
  payload: result.payload, // Full payload for debugging,
609
- suggestedResponses: result.suggestedResponses,
645
+ suggestedResponses: result.suggestedResponses
610
646
  });
611
647
  // Stage 2: Check for task graph (multi-step orchestration)
612
648
  if (result.payload?.taskGraph) {
@@ -614,7 +650,7 @@ export class MessageInputComponent {
614
650
  await this.handleTaskGraphExecution(userMessage, result, this.conversationId, conversationManagerMessage);
615
651
  // Remove CM from active tasks
616
652
  if (taskId) {
617
- this.activeTasks.remove(taskId);
653
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
618
654
  }
619
655
  }
620
656
  // Stage 3: Check for sub-agent invocation (single-step delegation)
@@ -623,7 +659,7 @@ export class MessageInputComponent {
623
659
  await this.handleSubAgentInvocation(userMessage, result, this.conversationId, conversationManagerMessage);
624
660
  // Remove CM from active tasks
625
661
  if (taskId) {
626
- this.activeTasks.remove(taskId);
662
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
627
663
  }
628
664
  }
629
665
  // Stage 4: Direct chat response from Sage
@@ -641,17 +677,15 @@ export class MessageInputComponent {
641
677
  versionId: '',
642
678
  versionNumber: 0,
643
679
  conversationDetailId: conversationManagerMessage.ID,
644
- name: '',
680
+ name: ''
645
681
  });
646
682
  console.log('🎨 Server created artifact, UI will reload to show it');
647
683
  this.messageSent.emit(conversationManagerMessage);
648
684
  }
649
- userMessage.Status = 'Complete';
650
- await userMessage.Save();
651
- this.messageSent.emit(userMessage);
685
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
652
686
  // Remove CM from active tasks
653
687
  if (taskId) {
654
- this.activeTasks.remove(taskId);
688
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
655
689
  }
656
690
  // Clean up completion timestamp after delay
657
691
  this.cleanupCompletionTimestamp(conversationManagerMessage.ID);
@@ -685,7 +719,7 @@ export class MessageInputComponent {
685
719
  }
686
720
  // Remove CM from active tasks
687
721
  if (taskId) {
688
- this.activeTasks.remove(taskId);
722
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
689
723
  }
690
724
  }
691
725
  }
@@ -693,23 +727,17 @@ export class MessageInputComponent {
693
727
  console.error('❌ Error processing message through agents:', error);
694
728
  // Update conversationManagerMessage status to Error
695
729
  if (conversationManagerMessage && conversationManagerMessage.ID) {
696
- // Mark as complete to stop progress updates
697
- this.markMessageComplete(conversationManagerMessage);
698
- conversationManagerMessage.Status = 'Error';
699
- conversationManagerMessage.Message = `❌ Error: ${String(error)}`;
730
+ // Use updateConversationDetail to ensure task cleanup
700
731
  conversationManagerMessage.Error = String(error);
701
- await conversationManagerMessage.Save();
702
- this.messageSent.emit(conversationManagerMessage);
732
+ await this.updateConversationDetail(conversationManagerMessage, `❌ Error: ${String(error)}`, 'Error');
703
733
  // Clean up completion timestamp
704
734
  this.cleanupCompletionTimestamp(conversationManagerMessage.ID);
705
735
  }
706
736
  // Mark user message as complete
707
- userMessage.Status = 'Complete';
708
- await userMessage.Save();
709
- this.messageSent.emit(userMessage);
737
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
710
738
  // Clean up active task
711
739
  if (taskId) {
712
- this.activeTasks.remove(taskId);
740
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
713
741
  }
714
742
  }
715
743
  }
@@ -724,9 +752,8 @@ export class MessageInputComponent {
724
752
  const taskCount = taskGraph.tasks?.length || 0;
725
753
  console.log(`📋 Task graph execution requested: ${workflowName}`, {
726
754
  reasoning,
727
- taskCount,
755
+ taskCount
728
756
  });
729
- const md = new Metadata();
730
757
  // Deduplicate tasks by tempId (LLM sometimes returns duplicates)
731
758
  const seenTempIds = new Set();
732
759
  const uniqueTasks = taskGraph.tasks.filter((task) => {
@@ -800,31 +827,27 @@ export class MessageInputComponent {
800
827
  conversationDetailId: taskExecutionMessage.ID, // Link tasks to execution message, not CM message
801
828
  environmentId: environmentId,
802
829
  sessionId: sessionId,
803
- createNotifications: true,
830
+ createNotifications: true
804
831
  };
805
832
  const result = await GraphQLDataProvider.Instance.ExecuteGQL(mutation, variables);
806
833
  console.log('📊 ExecuteTaskGraph result:', {
807
834
  hasExecuteTaskGraph: !!result?.ExecuteTaskGraph,
808
835
  success: result?.ExecuteTaskGraph?.success,
809
836
  resultsCount: result?.ExecuteTaskGraph?.results?.length,
810
- result: result,
837
+ result: result
811
838
  });
812
839
  // Step 4: Update task execution message with results
813
840
  // ExecuteGQL returns data directly (not wrapped in {data, errors})
814
841
  if (result?.ExecuteTaskGraph?.success) {
815
842
  console.log('✅ Task graph execution completed successfully');
816
- taskExecutionMessage.Message = `✅ **${workflowName}** completed successfully`;
817
- taskExecutionMessage.Status = 'Complete';
843
+ await this.updateConversationDetail(taskExecutionMessage, `✅ **${workflowName}** completed successfully`, 'Complete');
818
844
  }
819
845
  else {
820
846
  const errorMsg = result?.ExecuteTaskGraph?.errorMessage || 'Unknown error';
821
847
  console.error('❌ Task graph execution failed:', errorMsg);
822
- taskExecutionMessage.Message = `❌ **${workflowName}** failed: ${errorMsg}`;
823
- taskExecutionMessage.Status = 'Error';
824
848
  taskExecutionMessage.Error = errorMsg;
849
+ await this.updateConversationDetail(taskExecutionMessage, `❌ **${workflowName}** failed: ${errorMsg}`, 'Error');
825
850
  }
826
- await taskExecutionMessage.Save();
827
- this.messageSent.emit(taskExecutionMessage);
828
851
  // Trigger artifact reload for this message
829
852
  // Artifacts were created on server during task execution and linked to this message
830
853
  // This event triggers the parent component to reload artifacts from the database
@@ -833,45 +856,46 @@ export class MessageInputComponent {
833
856
  versionId: '',
834
857
  versionNumber: 1,
835
858
  conversationDetailId: taskExecutionMessage.ID,
836
- name: '',
859
+ name: ''
837
860
  });
838
861
  // Unregister from real-time updates (task complete)
839
862
  this.activeTaskExecutionMessageIds.delete(taskExecutionMessage.ID);
863
+ // Mark agent response message as complete (removes task from active tasks)
864
+ await this.updateConversationDetail(conversationManagerMessage, conversationManagerMessage.Message, 'Complete');
840
865
  // Mark user message as complete
841
- userMessage.Status = 'Complete';
842
- await userMessage.Save();
843
- this.messageSent.emit(userMessage);
866
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
844
867
  }
845
868
  catch (error) {
846
869
  console.error('❌ Error executing task graph:', error);
847
- taskExecutionMessage.Message = `❌ **${workflowName}** - Error: ${String(error)}`;
848
- taskExecutionMessage.Status = 'Error';
849
870
  taskExecutionMessage.Error = String(error);
850
- await taskExecutionMessage.Save();
851
- this.messageSent.emit(taskExecutionMessage);
871
+ await this.updateConversationDetail(taskExecutionMessage, `❌ **${workflowName}** - Error: ${String(error)}`, 'Error');
852
872
  // Trigger artifact reload even on error - partial artifacts may have been created
853
873
  this.artifactCreated.emit({
854
874
  artifactId: '',
855
875
  versionId: '',
856
876
  versionNumber: 1,
857
877
  conversationDetailId: taskExecutionMessage.ID,
858
- name: '',
878
+ name: ''
859
879
  });
860
880
  // Unregister from real-time updates (task failed)
861
881
  this.activeTaskExecutionMessageIds.delete(taskExecutionMessage.ID);
862
- userMessage.Status = 'Complete';
863
- await userMessage.Save();
864
- this.messageSent.emit(userMessage);
882
+ // Mark agent response message as complete (removes task from active tasks)
883
+ conversationManagerMessage.Error = String(error);
884
+ await this.updateConversationDetail(conversationManagerMessage, conversationManagerMessage.Message, 'Error');
885
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
865
886
  }
866
887
  }
867
888
  async updateConversationDetail(convoDetail, message, status, suggestedResponses) {
868
- if (convoDetail.Status === 'Complete' || convoDetail.Status === 'Error') {
869
- return; // Do not update completed or errored messages
870
- }
871
- // Mark as completing BEFORE updating if status is Complete or Error
889
+ // Mark as completing FIRST if status is Complete or Error
890
+ // This ensures task cleanup happens even if we return early due to guard clause
872
891
  if (status === 'Complete' || status === 'Error') {
873
892
  this.markMessageComplete(convoDetail);
874
893
  }
894
+ // Guard clause: Don't re-save if already complete/errored (prevents duplicate saves)
895
+ // Task has already been removed by markMessageComplete() above
896
+ if (convoDetail.Status === 'Complete' || convoDetail.Status === 'Error') {
897
+ return; // Already complete, no need to save again
898
+ }
875
899
  const maxAttempts = 2;
876
900
  let attempts = 0, done = false;
877
901
  while (attempts < maxAttempts && !done) {
@@ -903,7 +927,7 @@ export class MessageInputComponent {
903
927
  agentName, conversationId, conversationManagerMessage) {
904
928
  try {
905
929
  // Look up the agent
906
- const agent = AIEngineBase.Instance.Agents.find((a) => a.Name === agentName);
930
+ const agent = AIEngineBase.Instance.Agents.find(a => a.Name === agentName);
907
931
  if (!agent) {
908
932
  throw new Error(`Agent not found: ${agentName}`);
909
933
  }
@@ -924,15 +948,17 @@ export class MessageInputComponent {
924
948
  status: 'Starting...',
925
949
  relatedMessageId: userMessage.ID,
926
950
  conversationDetailId: agentResponseMessage.ID,
951
+ conversationId: this.conversationId,
952
+ conversationName: this.conversationName
927
953
  });
928
954
  // Invoke agent with task's input payload
929
955
  const agentResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.conversationHistory, task.description || task.name, agentResponseMessage.ID, task.inputPayload, // Pass the task's input payload
930
956
  this.createProgressCallback(agentResponseMessage, agentName));
931
- // Remove from active tasks
932
- this.activeTasks.remove(newTaskId);
957
+ // Task will be removed automatically in markMessageComplete() when status changes to Complete/Error
958
+ // DO NOT remove here - allows UI to show task during entire execution
933
959
  if (agentResult && agentResult.success) {
934
960
  // Update message with result
935
- await this.updateConversationDetail(agentResponseMessage, agentResult.agentRun?.Message || `✅ **${agentName}** completed`, 'Complete');
961
+ await this.updateConversationDetail(agentResponseMessage, agentResult.agentRun?.Message || `✅ **${agentName}** completed`, 'Complete', agentResult.suggestedResponses);
936
962
  // Server created artifacts - emit event to trigger UI reload
937
963
  if (agentResult.payload && Object.keys(agentResult.payload).length > 0) {
938
964
  this.artifactCreated.emit({
@@ -940,7 +966,7 @@ export class MessageInputComponent {
940
966
  versionId: '',
941
967
  versionNumber: 0,
942
968
  conversationDetailId: agentResponseMessage.ID,
943
- name: '',
969
+ name: ''
944
970
  });
945
971
  console.log('🎨 Server created artifact from single task execution');
946
972
  this.messageSent.emit(agentResponseMessage);
@@ -949,22 +975,15 @@ export class MessageInputComponent {
949
975
  else {
950
976
  // Handle failure
951
977
  const errorMsg = agentResult?.agentRun?.ErrorMessage || 'Agent execution failed';
952
- agentResponseMessage.Message = `❌ **${agentName}** failed: ${errorMsg}`;
953
- agentResponseMessage.Status = 'Error';
954
978
  agentResponseMessage.Error = errorMsg;
955
- await agentResponseMessage.Save();
956
- this.messageSent.emit(agentResponseMessage);
979
+ await this.updateConversationDetail(agentResponseMessage, `❌ **${agentName}** failed: ${errorMsg}`, 'Error');
957
980
  }
958
981
  // Mark user message as complete
959
- userMessage.Status = 'Complete';
960
- await userMessage.Save();
961
- this.messageSent.emit(userMessage);
982
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
962
983
  }
963
984
  catch (error) {
964
985
  console.error('❌ Error in single task execution:', error);
965
- userMessage.Status = 'Complete';
966
- await userMessage.Save();
967
- this.messageSent.emit(userMessage);
986
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
968
987
  }
969
988
  }
970
989
  /**
@@ -978,7 +997,7 @@ export class MessageInputComponent {
978
997
  // Now create a NEW message for the sub-agent execution
979
998
  try {
980
999
  // Look up the agent to get its ID
981
- const agent = AIEngineBase.Instance.Agents.find((a) => a.Name === agentName);
1000
+ const agent = AIEngineBase.Instance.Agents.find(a => a.Name === agentName);
982
1001
  // Create AI response message BEFORE invoking agent (for duration tracking)
983
1002
  const agentResponseMessage = await this.dataCache.createConversationDetail(this.currentUser);
984
1003
  agentResponseMessage.ConversationID = conversationId;
@@ -1000,19 +1019,21 @@ export class MessageInputComponent {
1000
1019
  status: 'Starting...',
1001
1020
  relatedMessageId: userMessage.ID,
1002
1021
  conversationDetailId: agentResponseMessage.ID,
1022
+ conversationId: this.conversationId,
1023
+ conversationName: this.conversationName
1003
1024
  });
1004
1025
  // Invoke the sub-agent with progress callback
1005
1026
  const subResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.conversationHistory, reasoning, agentResponseMessage.ID, undefined, // no payload for initial invocation
1006
1027
  this.createProgressCallback(agentResponseMessage, agentName));
1007
- // Remove from active tasks
1008
- this.activeTasks.remove(newTaskId);
1028
+ // Task will be removed automatically in markMessageComplete() when status changes to Complete/Error
1029
+ // DO NOT remove here - allows UI to show task during entire execution
1009
1030
  if (subResult && subResult.success) {
1010
1031
  // Update the response message with agent result
1011
1032
  // Store the agent ID for display
1012
1033
  if (subResult.agentRun.AgentID) {
1013
1034
  agentResponseMessage.AgentID = subResult.agentRun.AgentID;
1014
1035
  }
1015
- await this.updateConversationDetail(agentResponseMessage, subResult.agentRun?.Message || `✅ **${agentName}** completed`, 'Complete');
1036
+ await this.updateConversationDetail(agentResponseMessage, subResult.agentRun?.Message || `✅ **${agentName}** completed`, 'Complete', subResult.suggestedResponses);
1016
1037
  // Server created artifacts - emit event to trigger UI reload
1017
1038
  if (subResult.payload && Object.keys(subResult.payload).length > 0) {
1018
1039
  this.artifactCreated.emit({
@@ -1020,23 +1041,21 @@ export class MessageInputComponent {
1020
1041
  versionId: '',
1021
1042
  versionNumber: 0,
1022
1043
  conversationDetailId: agentResponseMessage.ID,
1023
- name: '',
1044
+ name: ''
1024
1045
  });
1025
1046
  console.log('🎨 Server created artifact for sub-agent message:', agentResponseMessage.ID);
1026
1047
  // Re-emit to trigger artifact display
1027
1048
  this.messageSent.emit(agentResponseMessage);
1028
1049
  }
1029
1050
  // Mark user message as complete
1030
- userMessage.Status = 'Complete';
1031
- await userMessage.Save();
1032
- this.messageSent.emit(userMessage);
1051
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1033
1052
  }
1034
1053
  else {
1035
1054
  // Sub-agent failed - attempt auto-retry once
1036
1055
  console.log(`⚠️ ${agentName} failed, attempting auto-retry...`);
1037
1056
  await this.updateConversationDetail(conversationManagerMessage, `👉 **${agentName}** will handle this request...\n\n⚠️ First attempt failed, retrying...`, conversationManagerMessage.Status);
1038
1057
  // Update the existing agentResponseMessage to show retry status
1039
- await this.updateConversationDetail(agentResponseMessage, 'Retrying...', agentResponseMessage.Status);
1058
+ await this.updateConversationDetail(agentResponseMessage, "Retrying...", agentResponseMessage.Status);
1040
1059
  // Retry the sub-agent
1041
1060
  const retryResult = await this.agentService.invokeSubAgent(agentName, conversationId, userMessage, this.conversationHistory, reasoning, agentResponseMessage.ID, undefined, // no payload for retry
1042
1061
  this.createProgressCallback(agentResponseMessage, `${agentName} (retry)`));
@@ -1053,37 +1072,25 @@ export class MessageInputComponent {
1053
1072
  versionId: '',
1054
1073
  versionNumber: 0,
1055
1074
  conversationDetailId: agentResponseMessage.ID,
1056
- name: '',
1075
+ name: ''
1057
1076
  });
1058
1077
  this.messageSent.emit(agentResponseMessage);
1059
1078
  }
1060
- userMessage.Status = 'Complete';
1061
- await userMessage.Save();
1062
- this.messageSent.emit(userMessage);
1079
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1063
1080
  }
1064
1081
  else {
1065
1082
  // Retry also failed - show error with manual retry option
1066
- conversationManagerMessage.Status = 'Error';
1067
- conversationManagerMessage.Message = `❌ **${agentName}** failed after retry\n\n${retryResult?.agentRun?.ErrorMessage || 'Unknown error'}`;
1068
1083
  conversationManagerMessage.Error = retryResult?.agentRun?.ErrorMessage || null;
1069
- await conversationManagerMessage.Save();
1070
- this.messageSent.emit(conversationManagerMessage);
1071
- userMessage.Status = 'Complete'; // Don't mark user message as error
1072
- await userMessage.Save();
1073
- this.messageSent.emit(userMessage);
1084
+ await this.updateConversationDetail(conversationManagerMessage, `❌ **${agentName}** failed after retry\n\n${retryResult?.agentRun?.ErrorMessage || 'Unknown error'}`, 'Error');
1085
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1074
1086
  }
1075
1087
  }
1076
1088
  }
1077
1089
  catch (error) {
1078
1090
  console.error(`❌ Error invoking sub-agent ${agentName}:`, error);
1079
- conversationManagerMessage.Status = 'Error';
1080
- conversationManagerMessage.Message = `❌ **${agentName}** encountered an error\n\n${String(error)}`;
1081
1091
  conversationManagerMessage.Error = String(error);
1082
- await conversationManagerMessage.Save();
1083
- this.messageSent.emit(conversationManagerMessage);
1084
- userMessage.Status = 'Complete'; // Don't mark user message as error
1085
- await userMessage.Save();
1086
- this.messageSent.emit(userMessage);
1092
+ await this.updateConversationDetail(conversationManagerMessage, `❌ **${agentName}** encountered an error\n\n${String(error)}`, 'Error');
1093
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1087
1094
  }
1088
1095
  }
1089
1096
  /**
@@ -1095,63 +1102,46 @@ export class MessageInputComponent {
1095
1102
  const lastAIMessage = this.conversationHistory
1096
1103
  .slice()
1097
1104
  .reverse()
1098
- .find((msg) => msg.Role === 'AI' && msg.AgentID && msg.AgentID !== this.converationManagerAgent?.ID);
1105
+ .find(msg => msg.Role === 'AI' &&
1106
+ msg.AgentID &&
1107
+ msg.AgentID !== this.converationManagerAgent?.ID);
1099
1108
  if (!lastAIMessage || !lastAIMessage.AgentID) {
1100
1109
  // No previous specialist agent - just mark user message as complete
1101
1110
  console.log('🔇 No previous specialist agent found - marking complete');
1102
- userMessage.Status = 'Complete';
1103
- await userMessage.Save();
1104
- this.messageSent.emit(userMessage);
1111
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1105
1112
  return;
1106
1113
  }
1107
1114
  // Load the agent entity to get its name
1108
- const rv = new RunView();
1109
- const agentResult = await rv.RunView({
1110
- EntityName: 'AI Agents',
1111
- ExtraFilter: `ID='${lastAIMessage.AgentID}'`,
1112
- ResultType: 'entity_object',
1113
- }, this.currentUser);
1114
- if (!agentResult.Success || !agentResult.Results || agentResult.Results.length === 0) {
1115
+ const previousAgent = AIEngineBase.Instance.Agents.find(a => a.ID === lastAIMessage.AgentID);
1116
+ if (!previousAgent) {
1115
1117
  console.warn('⚠️ Could not load previous agent - marking complete');
1116
- userMessage.Status = 'Complete';
1117
- await userMessage.Save();
1118
- this.messageSent.emit(userMessage);
1118
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1119
1119
  return;
1120
1120
  }
1121
- const previousAgent = agentResult.Results[0];
1122
1121
  const agentName = previousAgent.Name || 'Agent';
1123
1122
  console.log(`🔄 Agent continuity: Continuing with ${agentName} (AgentID: ${lastAIMessage.AgentID})`);
1124
- // Load the OUTPUT artifact from the last agent message
1125
- const artifactResult = await rv.RunView({
1126
- EntityName: 'MJ: Conversation Detail Artifacts',
1127
- ExtraFilter: `ConversationDetailID='${lastAIMessage.ID}' AND Direction='Output'`,
1128
- ResultType: 'entity_object',
1129
- }, this.currentUser);
1130
1123
  let previousPayload = null;
1131
1124
  let previousArtifactInfo = null;
1132
- if (artifactResult.Success && artifactResult.Results && artifactResult.Results.length > 0) {
1133
- // Load the artifact version content
1134
- const junctionRecord = artifactResult.Results[0];
1135
- const versionResult = await rv.RunView({
1136
- EntityName: 'MJ: Artifact Versions',
1137
- ExtraFilter: `ID='${junctionRecord.ArtifactVersionID}'`,
1138
- ResultType: 'entity_object',
1139
- }, this.currentUser);
1140
- if (versionResult.Success && versionResult.Results && versionResult.Results.length > 0) {
1141
- const version = versionResult.Results[0];
1142
- if (version.Content) {
1143
- try {
1125
+ // Use pre-loaded artifact data (no DB queries!)
1126
+ if (this.artifactsByDetailId) {
1127
+ const artifacts = this.artifactsByDetailId.get(lastAIMessage.ID);
1128
+ if (artifacts && artifacts.length > 0) {
1129
+ try {
1130
+ // Use the first artifact (should only be one OUTPUT per message)
1131
+ const artifact = artifacts[0];
1132
+ const version = await artifact.getVersion();
1133
+ if (version.Content) {
1144
1134
  previousPayload = JSON.parse(version.Content);
1145
1135
  previousArtifactInfo = {
1146
- artifactId: version.ArtifactID,
1147
- versionId: version.ID,
1148
- versionNumber: version.VersionNumber || 1,
1136
+ artifactId: artifact.artifactId,
1137
+ versionId: artifact.artifactVersionId,
1138
+ versionNumber: artifact.versionNumber
1149
1139
  };
1150
1140
  console.log('📦 Loaded previous OUTPUT artifact as payload for continuity', previousArtifactInfo);
1151
1141
  }
1152
- catch (error) {
1153
- console.warn('⚠️ Could not parse previous artifact content:', error);
1154
- }
1142
+ }
1143
+ catch (error) {
1144
+ console.warn('⚠️ Could not parse previous artifact content:', error);
1155
1145
  }
1156
1146
  }
1157
1147
  }
@@ -1172,12 +1162,14 @@ export class MessageInputComponent {
1172
1162
  status: 'Processing refinement...',
1173
1163
  relatedMessageId: userMessage.ID,
1174
1164
  conversationDetailId: statusMessage.ID,
1165
+ conversationId: this.conversationId,
1166
+ conversationName: this.conversationName
1175
1167
  });
1176
1168
  try {
1177
1169
  // Invoke the agent with the previous payload
1178
1170
  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);
1179
1171
  // Remove from active tasks
1180
- this.activeTasks.remove(taskId);
1172
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
1181
1173
  if (continuityResult && continuityResult.success) {
1182
1174
  // Create response message
1183
1175
  const agentResponseMessage = await this.dataCache.createConversationDetail(this.currentUser);
@@ -1197,39 +1189,27 @@ export class MessageInputComponent {
1197
1189
  versionId: '',
1198
1190
  versionNumber: 0,
1199
1191
  conversationDetailId: agentResponseMessage.ID,
1200
- name: '',
1192
+ name: ''
1201
1193
  });
1202
1194
  console.log('🎨 Server created artifact (versioned) from agent continuity');
1203
1195
  this.messageSent.emit(agentResponseMessage);
1204
1196
  }
1205
1197
  // Mark user message as complete
1206
- userMessage.Status = 'Complete';
1207
- await userMessage.Save();
1208
- this.messageSent.emit(userMessage);
1198
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1209
1199
  }
1210
1200
  else {
1211
1201
  // Agent failed
1212
- statusMessage.Status = 'Error';
1213
- statusMessage.Message = `❌ **${agentName}** failed during refinement\n\n${continuityResult?.agentRun?.ErrorMessage || 'Unknown error'}`;
1214
1202
  statusMessage.Error = continuityResult?.agentRun?.ErrorMessage || null;
1215
- await statusMessage.Save();
1216
- this.messageSent.emit(statusMessage);
1217
- userMessage.Status = 'Complete';
1218
- await userMessage.Save();
1219
- this.messageSent.emit(userMessage);
1203
+ await this.updateConversationDetail(statusMessage, `❌ **${agentName}** failed during refinement\n\n${continuityResult?.agentRun?.ErrorMessage || 'Unknown error'}`, 'Error');
1204
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1220
1205
  }
1221
1206
  }
1222
1207
  catch (error) {
1223
1208
  console.error(`❌ Error in agent continuity with ${agentName}:`, error);
1224
- this.activeTasks.remove(taskId);
1225
- statusMessage.Status = 'Error';
1226
- statusMessage.Message = `❌ **${agentName}** encountered an error\n\n${String(error)}`;
1209
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
1227
1210
  statusMessage.Error = String(error);
1228
- await statusMessage.Save();
1229
- this.messageSent.emit(statusMessage);
1230
- userMessage.Status = 'Complete';
1231
- await userMessage.Save();
1232
- this.messageSent.emit(userMessage);
1211
+ await this.updateConversationDetail(statusMessage, `❌ **${agentName}** encountered an error\n\n${String(error)}`, 'Error');
1212
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1233
1213
  }
1234
1214
  }
1235
1215
  /**
@@ -1244,16 +1224,20 @@ export class MessageInputComponent {
1244
1224
  status: 'Processing...',
1245
1225
  relatedMessageId: userMessage.ID,
1246
1226
  conversationDetailId: userMessage.ID,
1227
+ conversationId: this.conversationId,
1228
+ conversationName: this.conversationName
1247
1229
  });
1230
+ // Declare agentResponseMessage outside try block so it's accessible in catch
1231
+ let agentResponseMessage = undefined;
1248
1232
  try {
1249
1233
  // Update user message status to In-Progress
1250
1234
  userMessage.Status = 'In-Progress';
1251
1235
  await userMessage.Save();
1252
1236
  this.messageSent.emit(userMessage);
1253
1237
  // Look up the agent to get its ID
1254
- const agent = AIEngineBase.Instance.Agents.find((a) => a.Name === agentName);
1238
+ const agent = AIEngineBase.Instance.Agents.find(a => a.Name === agentName);
1255
1239
  // Create AI response message BEFORE invoking agent (for duration tracking)
1256
- const agentResponseMessage = await this.dataCache.createConversationDetail(this.currentUser);
1240
+ agentResponseMessage = await this.dataCache.createConversationDetail(this.currentUser);
1257
1241
  agentResponseMessage.ConversationID = conversationId;
1258
1242
  agentResponseMessage.Role = 'AI';
1259
1243
  agentResponseMessage.Message = '⏳ Starting...'; // Initial message
@@ -1271,7 +1255,7 @@ export class MessageInputComponent {
1271
1255
  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
1272
1256
  this.createProgressCallback(agentResponseMessage, agentName));
1273
1257
  // Remove from active tasks
1274
- this.activeTasks.remove(taskId);
1258
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
1275
1259
  if (result && result.success) {
1276
1260
  if (result.agentRun.AgentID) {
1277
1261
  agentResponseMessage.AgentID = result.agentRun.AgentID;
@@ -1289,7 +1273,7 @@ export class MessageInputComponent {
1289
1273
  }
1290
1274
  // Stage 3: Normal chat response
1291
1275
  else {
1292
- await this.updateConversationDetail(agentResponseMessage, result.agentRun?.Message || `✅ **${agentName}** completed`, 'Complete');
1276
+ await this.updateConversationDetail(agentResponseMessage, result.agentRun?.Message || `✅ **${agentName}** completed`, 'Complete', result.suggestedResponses);
1293
1277
  // Server created artifacts - emit event to trigger UI reload
1294
1278
  if (result.payload && Object.keys(result.payload).length > 0) {
1295
1279
  this.artifactCreated.emit({
@@ -1297,108 +1281,105 @@ export class MessageInputComponent {
1297
1281
  versionId: '',
1298
1282
  versionNumber: 0,
1299
1283
  conversationDetailId: agentResponseMessage.ID,
1300
- name: '',
1284
+ name: ''
1301
1285
  });
1302
1286
  this.messageSent.emit(agentResponseMessage);
1303
1287
  }
1304
1288
  // Mark user message as complete
1305
- userMessage.Status = 'Complete';
1306
- await userMessage.Save();
1307
- this.messageSent.emit(userMessage);
1289
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1308
1290
  }
1309
1291
  }
1310
1292
  else {
1311
- // Agent failed - create error message
1312
- const errorMessage = await this.dataCache.createConversationDetail(this.currentUser);
1313
- errorMessage.ConversationID = conversationId;
1314
- errorMessage.Role = 'AI';
1315
- errorMessage.Message = `❌ **@${agentName}** failed\n\n${result?.agentRun?.ErrorMessage || 'Unknown error'}`;
1316
- errorMessage.ParentID = userMessage.ID;
1317
- errorMessage.Status = 'Error';
1318
- errorMessage.Error = result?.agentRun?.ErrorMessage || null;
1319
- errorMessage.HiddenToUser = false;
1320
- await errorMessage.Save();
1321
- this.messageSent.emit(errorMessage);
1322
- userMessage.Status = 'Complete';
1323
- await userMessage.Save();
1324
- this.messageSent.emit(userMessage);
1293
+ // Agent failed - update the existing message instead of creating a new one
1294
+ agentResponseMessage.Error = result?.agentRun?.ErrorMessage || null;
1295
+ await this.updateConversationDetail(agentResponseMessage, `❌ **@${agentName}** failed\n\n${result?.agentRun?.ErrorMessage || 'Unknown error'}`, 'Error');
1296
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1325
1297
  }
1326
1298
  }
1327
1299
  catch (error) {
1328
1300
  console.error(`❌ Error invoking mentioned agent ${agentName}:`, error);
1329
- this.activeTasks.remove(taskId);
1330
- const errorMessage = await this.dataCache.createConversationDetail(this.currentUser);
1331
- errorMessage.ConversationID = conversationId;
1332
- errorMessage.Role = 'AI';
1333
- errorMessage.Message = `❌ **@${agentName}** encountered an error\n\n${String(error)}`;
1334
- errorMessage.ParentID = userMessage.ID;
1335
- errorMessage.Status = 'Error';
1336
- errorMessage.Error = String(error);
1337
- errorMessage.HiddenToUser = false;
1338
- await errorMessage.Save();
1339
- this.messageSent.emit(errorMessage);
1340
- userMessage.Status = 'Complete';
1341
- await userMessage.Save();
1342
- this.messageSent.emit(userMessage);
1301
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
1302
+ // Update the existing agent response message if it was created
1303
+ if (agentResponseMessage) {
1304
+ agentResponseMessage.Error = String(error);
1305
+ await this.updateConversationDetail(agentResponseMessage, `❌ **@${agentName}** encountered an error\n\n${String(error)}`, 'Error');
1306
+ }
1307
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1343
1308
  }
1344
1309
  }
1345
1310
  /**
1346
1311
  * Continue with the same agent from previous message (implicit continuation)
1347
1312
  * Bypasses Sage - no status messages
1313
+ *
1314
+ * @param targetArtifactVersionId Optional specific artifact version to use as payload (from intent check)
1348
1315
  */
1349
- async continueWithAgent(userMessage, agentId, conversationId) {
1316
+ async continueWithAgent(userMessage, agentId, conversationId, targetArtifactVersionId) {
1350
1317
  // Load the agent entity to get its name
1351
- const rv = new RunView();
1352
- const agentResult = await rv.RunView({
1353
- EntityName: 'AI Agents',
1354
- ExtraFilter: `ID='${agentId}'`,
1355
- ResultType: 'entity_object',
1356
- }, this.currentUser);
1357
- if (!agentResult.Success || !agentResult.Results || agentResult.Results.length === 0) {
1318
+ const agent = AIEngineBase.Instance.Agents.find(a => a.ID === agentId);
1319
+ if (!agent) {
1358
1320
  console.warn('⚠️ Could not load agent for continuation - falling back to Sage');
1359
1321
  await this.processMessageThroughAgent(userMessage, { mentions: [], agentMention: null, userMentions: [] });
1360
1322
  return;
1361
1323
  }
1362
- const agent = agentResult.Results[0];
1363
1324
  const agentName = agent.Name || 'Agent';
1364
- // Find the last AI message from this same agent to get the previous OUTPUT artifact
1365
- const lastAIMessage = this.conversationHistory
1366
- .slice()
1367
- .reverse()
1368
- .find((msg) => msg.Role === 'AI' && msg.AgentID === agentId);
1369
1325
  let previousPayload = null;
1370
1326
  let previousArtifactInfo = null;
1371
- if (lastAIMessage) {
1372
- // Load the OUTPUT artifact from the last agent message
1373
- const artifactResult = await rv.RunView({
1374
- EntityName: 'MJ: Conversation Detail Artifacts',
1375
- ExtraFilter: `ConversationDetailID='${lastAIMessage.ID}' AND Direction='Output'`,
1376
- ResultType: 'entity_object',
1377
- }, this.currentUser);
1378
- if (artifactResult.Success && artifactResult.Results && artifactResult.Results.length > 0) {
1379
- // Load the artifact version content
1380
- const junctionRecord = artifactResult.Results[0];
1381
- const versionResult = await rv.RunView({
1382
- EntityName: 'MJ: Artifact Versions',
1383
- ExtraFilter: `ID='${junctionRecord.ArtifactVersionID}'`,
1384
- ResultType: 'entity_object',
1385
- }, this.currentUser);
1386
- if (versionResult.Success && versionResult.Results && versionResult.Results.length > 0) {
1387
- const version = versionResult.Results[0];
1388
- if (version.Content) {
1389
- try {
1327
+ // Use targetArtifactVersionId if specified (from intent check)
1328
+ if (targetArtifactVersionId && this.artifactsByDetailId) {
1329
+ console.log('🎯 Using target artifact version from intent check:', targetArtifactVersionId);
1330
+ // Find the artifact in pre-loaded data (O(n) search across all messages)
1331
+ for (const [detailId, artifacts] of this.artifactsByDetailId.entries()) {
1332
+ const targetArtifact = artifacts.find(a => a.artifactVersionId === targetArtifactVersionId);
1333
+ if (targetArtifact) {
1334
+ try {
1335
+ // Lazy load the full version entity to get Content
1336
+ const version = await targetArtifact.getVersion();
1337
+ if (version.Content) {
1390
1338
  previousPayload = JSON.parse(version.Content);
1391
1339
  previousArtifactInfo = {
1392
- artifactId: version.ArtifactID,
1393
- versionId: version.ID,
1394
- versionNumber: version.VersionNumber || 1,
1340
+ artifactId: targetArtifact.artifactId,
1341
+ versionId: targetArtifact.artifactVersionId,
1342
+ versionNumber: targetArtifact.versionNumber
1395
1343
  };
1396
- console.log('📦 Loaded previous OUTPUT artifact as payload for continuation', previousArtifactInfo);
1344
+ console.log('📦 Loaded target artifact version as payload', previousArtifactInfo);
1397
1345
  }
1398
- catch (error) {
1399
- console.warn('⚠️ Could not parse previous artifact content:', error);
1346
+ }
1347
+ catch (error) {
1348
+ console.warn('⚠️ Could not load target artifact version:', error);
1349
+ }
1350
+ break;
1351
+ }
1352
+ }
1353
+ }
1354
+ // Fall back to most recent artifact if no target specified or target not found
1355
+ if (!previousPayload) {
1356
+ console.log('📦 Using most recent artifact from last agent message');
1357
+ // Find the last AI message from this same agent
1358
+ const lastAIMessage = this.conversationHistory
1359
+ .slice()
1360
+ .reverse()
1361
+ .find(msg => msg.Role === 'AI' && msg.AgentID === agentId);
1362
+ if (lastAIMessage && this.artifactsByDetailId) {
1363
+ // Get artifacts from pre-loaded data (no DB query!)
1364
+ const artifacts = this.artifactsByDetailId.get(lastAIMessage.ID);
1365
+ if (artifacts && artifacts.length > 0) {
1366
+ try {
1367
+ // Use the first artifact (should only be one OUTPUT per message)
1368
+ const artifact = artifacts[0];
1369
+ const version = await artifact.getVersion();
1370
+ if (version.Content) {
1371
+ previousPayload = JSON.parse(version.Content);
1372
+ previousArtifactInfo = {
1373
+ artifactId: artifact.artifactId,
1374
+ versionId: artifact.artifactVersionId,
1375
+ versionNumber: artifact.versionNumber
1376
+ };
1377
+ console.log('📦 Loaded most recent artifact as payload', previousArtifactInfo);
1400
1378
  }
1401
1379
  }
1380
+ catch (error) {
1381
+ console.warn('⚠️ Could not parse artifact content:', error);
1382
+ }
1402
1383
  }
1403
1384
  }
1404
1385
  }
@@ -1408,14 +1389,18 @@ export class MessageInputComponent {
1408
1389
  status: 'Processing...',
1409
1390
  relatedMessageId: userMessage.ID,
1410
1391
  conversationDetailId: userMessage.ID,
1392
+ conversationId: this.conversationId,
1393
+ conversationName: this.conversationName
1411
1394
  });
1395
+ // Declare agentResponseMessage outside try block so it's accessible in catch
1396
+ let agentResponseMessage = undefined;
1412
1397
  try {
1413
1398
  // Update user message status to In-Progress
1414
1399
  userMessage.Status = 'In-Progress';
1415
1400
  await userMessage.Save();
1416
1401
  this.messageSent.emit(userMessage);
1417
1402
  // Create AI response message BEFORE invoking agent (for duration tracking)
1418
- const agentResponseMessage = await this.dataCache.createConversationDetail(this.currentUser);
1403
+ agentResponseMessage = await this.dataCache.createConversationDetail(this.currentUser);
1419
1404
  agentResponseMessage.ConversationID = conversationId;
1420
1405
  agentResponseMessage.Role = 'AI';
1421
1406
  agentResponseMessage.Message = '⏳ Starting...'; // Initial message
@@ -1430,10 +1415,10 @@ export class MessageInputComponent {
1430
1415
  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
1431
1416
  this.createProgressCallback(agentResponseMessage, agentName), previousArtifactInfo?.artifactId, previousArtifactInfo?.versionId);
1432
1417
  // Remove from active tasks
1433
- this.activeTasks.remove(taskId);
1418
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
1434
1419
  if (result && result.success) {
1435
1420
  // Update the response message with agent result
1436
- await this.updateConversationDetail(agentResponseMessage, result.agentRun?.Message || `✅ **${agentName}** completed`, 'Complete');
1421
+ await this.updateConversationDetail(agentResponseMessage, result.agentRun?.Message || `✅ **${agentName}** completed`, 'Complete', result.suggestedResponses);
1437
1422
  // Server created artifacts (handles versioning) - emit event to trigger UI reload
1438
1423
  if (result.payload && Object.keys(result.payload).length > 0) {
1439
1424
  this.artifactCreated.emit({
@@ -1441,48 +1426,29 @@ export class MessageInputComponent {
1441
1426
  versionId: '',
1442
1427
  versionNumber: 0,
1443
1428
  conversationDetailId: agentResponseMessage.ID,
1444
- name: '',
1429
+ name: ''
1445
1430
  });
1446
1431
  this.messageSent.emit(agentResponseMessage);
1447
1432
  }
1448
1433
  // Mark user message as complete
1449
- userMessage.Status = 'Complete';
1450
- await userMessage.Save();
1451
- this.messageSent.emit(userMessage);
1434
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1452
1435
  }
1453
1436
  else {
1454
- // Agent failed - create error message
1455
- const errorMessage = await this.dataCache.createConversationDetail(this.currentUser);
1456
- errorMessage.ConversationID = conversationId;
1457
- errorMessage.Role = 'AI';
1458
- errorMessage.Message = `❌ **${agentName}** failed\n\n${result?.agentRun?.ErrorMessage || 'Unknown error'}`;
1459
- errorMessage.ParentID = userMessage.ID;
1460
- errorMessage.Status = 'Error';
1461
- errorMessage.Error = result?.agentRun?.ErrorMessage || null;
1462
- errorMessage.HiddenToUser = false;
1463
- await errorMessage.Save();
1464
- this.messageSent.emit(errorMessage);
1465
- userMessage.Status = 'Complete';
1466
- await userMessage.Save();
1467
- this.messageSent.emit(userMessage);
1437
+ // Agent failed - update the existing message instead of creating a new one
1438
+ agentResponseMessage.Error = result?.agentRun?.ErrorMessage || null;
1439
+ await this.updateConversationDetail(agentResponseMessage, `❌ **${agentName}** failed\n\n${result?.agentRun?.ErrorMessage || 'Unknown error'}`, 'Error');
1440
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1468
1441
  }
1469
1442
  }
1470
1443
  catch (error) {
1471
1444
  console.error(`❌ Error continuing with agent ${agentName}:`, error);
1472
- this.activeTasks.remove(taskId);
1473
- const errorMessage = await this.dataCache.createConversationDetail(this.currentUser);
1474
- errorMessage.ConversationID = conversationId;
1475
- errorMessage.Role = 'AI';
1476
- errorMessage.Message = `❌ **${agentName}** encountered an error\n\n${String(error)}`;
1477
- errorMessage.ParentID = userMessage.ID;
1478
- errorMessage.Status = 'Error';
1479
- errorMessage.Error = String(error);
1480
- errorMessage.HiddenToUser = false;
1481
- await errorMessage.Save();
1482
- this.messageSent.emit(errorMessage);
1483
- userMessage.Status = 'Complete';
1484
- await userMessage.Save();
1485
- this.messageSent.emit(userMessage);
1445
+ // Task removed in markMessageComplete() - this.activeTasks.remove(taskId);
1446
+ // Update the existing agent response message if it was created
1447
+ if (agentResponseMessage) {
1448
+ agentResponseMessage.Error = String(error);
1449
+ await this.updateConversationDetail(agentResponseMessage, `❌ **${agentName}** encountered an error\n\n${String(error)}`, 'Error');
1450
+ }
1451
+ await this.updateConversationDetail(userMessage, userMessage.Message, 'Complete');
1486
1452
  }
1487
1453
  }
1488
1454
  /**
@@ -1493,7 +1459,7 @@ export class MessageInputComponent {
1493
1459
  console.log('🏷️ Naming conversation based on first message...');
1494
1460
  // Load the Name Conversation prompt to get its ID
1495
1461
  await AIEngineBase.Instance.Config(false);
1496
- const p = AIEngineBase.Instance.Prompts.find((pr) => pr.Name === 'Name Conversation');
1462
+ const p = AIEngineBase.Instance.Prompts.find(pr => pr.Name === 'Name Conversation');
1497
1463
  if (!p) {
1498
1464
  console.warn('⚠️ Name Conversation prompt not found');
1499
1465
  return;
@@ -1512,7 +1478,8 @@ export class MessageInputComponent {
1512
1478
  });
1513
1479
  if (result && result.success && (result.parsedResult || result.output)) {
1514
1480
  // Use parsedResult if available, otherwise parse output
1515
- const parsed = result.parsedResult || (result.output ? JSON.parse(result.output) : null);
1481
+ const parsed = result.parsedResult ||
1482
+ (result.output ? JSON.parse(result.output) : null);
1516
1483
  if (parsed) {
1517
1484
  const { name, description } = parsed;
1518
1485
  if (name) {
@@ -1524,7 +1491,7 @@ export class MessageInputComponent {
1524
1491
  this.conversationRenamed.emit({
1525
1492
  conversationId: this.conversationId,
1526
1493
  name: name,
1527
- description: description || '',
1494
+ description: description || ''
1528
1495
  });
1529
1496
  }
1530
1497
  }
@@ -1545,10 +1512,26 @@ export class MessageInputComponent {
1545
1512
  markMessageComplete(conversationDetail) {
1546
1513
  const now = Date.now();
1547
1514
  this.completionTimestamps.set(conversationDetail.ID, now);
1515
+ // Remove task from active tasks if it exists
1516
+ const task = this.activeTasks.getByConversationDetailId(conversationDetail.ID);
1517
+ if (task) {
1518
+ console.log(`✅ Task found for message ${conversationDetail.ID} - removing from active tasks:`, {
1519
+ taskId: task.id,
1520
+ agentName: task.agentName,
1521
+ conversationId: task.conversationId,
1522
+ conversationName: task.conversationName
1523
+ });
1524
+ this.activeTasks.remove(task.id);
1525
+ // Show completion notification
1526
+ MJNotificationService.Instance?.CreateSimpleNotification(`${task.agentName} completed in ${task.conversationName || 'conversation'}`, 'success', 3000);
1527
+ }
1528
+ else {
1529
+ console.warn(`⚠️ No task found for completed message ${conversationDetail.ID} - task may have been removed prematurely or not added`);
1530
+ }
1548
1531
  // Emit completion event to parent so it can refresh agent run data
1549
1532
  this.messageComplete.emit({
1550
1533
  conversationDetailId: conversationDetail.ID,
1551
- agentRunId: conversationDetail.AgentRunID,
1534
+ agentRunId: conversationDetail.AgentRunID
1552
1535
  });
1553
1536
  }
1554
1537
  /**
@@ -1566,7 +1549,7 @@ export class MessageInputComponent {
1566
1549
  } if (rf & 2) {
1567
1550
  let _t;
1568
1551
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.inputBox = _t.first);
1569
- } }, inputs: { conversationId: "conversationId", currentUser: "currentUser", disabled: "disabled", placeholder: "placeholder", parentMessageId: "parentMessageId", conversationHistory: "conversationHistory", initialMessage: "initialMessage" }, outputs: { messageSent: "messageSent", agentResponse: "agentResponse", agentRunDetected: "agentRunDetected", agentRunUpdate: "agentRunUpdate", messageComplete: "messageComplete", artifactCreated: "artifactCreated", conversationRenamed: "conversationRenamed", intentCheckStarted: "intentCheckStarted", intentCheckCompleted: "intentCheckCompleted" }, features: [i0.ɵɵNgOnChangesFeature], decls: 4, vars: 8, consts: [["inputBox", ""], [1, "message-input-wrapper"], ["class", "processing-indicator", 4, "ngIf"], [3, "valueChange", "textSubmitted", "placeholder", "disabled", "showCharacterCount", "enableMentions", "currentUser", "rows", "value"], [1, "processing-indicator"], [1, "fas", "fa-circle-notch", "fa-spin"]], template: function MessageInputComponent_Template(rf, ctx) { if (rf & 1) {
1552
+ } }, inputs: { conversationId: "conversationId", conversationName: "conversationName", currentUser: "currentUser", disabled: "disabled", placeholder: "placeholder", parentMessageId: "parentMessageId", conversationHistory: "conversationHistory", initialMessage: "initialMessage", artifactsByDetailId: "artifactsByDetailId", agentRunsByDetailId: "agentRunsByDetailId", inProgressMessageIds: "inProgressMessageIds" }, outputs: { messageSent: "messageSent", agentResponse: "agentResponse", agentRunDetected: "agentRunDetected", agentRunUpdate: "agentRunUpdate", messageComplete: "messageComplete", artifactCreated: "artifactCreated", conversationRenamed: "conversationRenamed", intentCheckStarted: "intentCheckStarted", intentCheckCompleted: "intentCheckCompleted" }, features: [i0.ɵɵNgOnChangesFeature], decls: 4, vars: 8, consts: [["inputBox", ""], [1, "message-input-wrapper"], ["class", "processing-indicator", 4, "ngIf"], [3, "valueChange", "textSubmitted", "placeholder", "disabled", "showCharacterCount", "enableMentions", "currentUser", "rows", "value"], [1, "processing-indicator"], [1, "fas", "fa-circle-notch", "fa-spin"]], template: function MessageInputComponent_Template(rf, ctx) { if (rf & 1) {
1570
1553
  const _r1 = i0.ɵɵgetCurrentView();
1571
1554
  i0.ɵɵelementStart(0, "div", 1);
1572
1555
  i0.ɵɵtemplate(1, MessageInputComponent_div_1_Template, 4, 1, "div", 2);
@@ -1587,6 +1570,8 @@ export class MessageInputComponent {
1587
1570
  args: [{ selector: 'mj-message-input', template: "<div class=\"message-input-wrapper\">\n <!-- Processing Indicator Overlay -->\n <div class=\"processing-indicator\" *ngIf=\"isProcessing\">\n <i class=\"fas fa-circle-notch fa-spin\"></i>\n <span>{{ processingMessage }}</span>\n </div>\n\n <!-- Message Input Box -->\n <mj-message-input-box\n #inputBox\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled || isProcessing\"\n [showCharacterCount]=\"false\"\n [enableMentions]=\"true\"\n [currentUser]=\"currentUser\"\n [rows]=\"3\"\n [(value)]=\"messageText\"\n (textSubmitted)=\"onTextSubmitted($event)\">\n </mj-message-input-box>\n</div>", styles: [".message-input-wrapper {\n position: relative;\n width: 100%;\n}\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: rgba(255, 255, 255, 0.95);\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n z-index: 10;\n pointer-events: none;\n\n i {\n color: var(--primary-color, #007bff);\n }\n\n span {\n font-size: 0.9rem;\n color: var(--text-primary, #333);\n }\n}"] }]
1588
1571
  }], () => [{ type: i1.DialogService }, { type: i2.ToastService }, { type: i3.ConversationAgentService }, { type: i4.ConversationStateService }, { type: i5.DataCacheService }, { type: i6.ActiveTasksService }, { type: i7.MentionParserService }, { type: i8.MentionAutocompleteService }], { conversationId: [{
1589
1572
  type: Input
1573
+ }], conversationName: [{
1574
+ type: Input
1590
1575
  }], currentUser: [{
1591
1576
  type: Input
1592
1577
  }], disabled: [{
@@ -1599,6 +1584,12 @@ export class MessageInputComponent {
1599
1584
  type: Input
1600
1585
  }], initialMessage: [{
1601
1586
  type: Input
1587
+ }], artifactsByDetailId: [{
1588
+ type: Input
1589
+ }], agentRunsByDetailId: [{
1590
+ type: Input
1591
+ }], inProgressMessageIds: [{
1592
+ type: Input
1602
1593
  }], messageSent: [{
1603
1594
  type: Output
1604
1595
  }], agentResponse: [{
@@ -1621,5 +1612,5 @@ export class MessageInputComponent {
1621
1612
  type: ViewChild,
1622
1613
  args: ['inputBox']
1623
1614
  }] }); })();
1624
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MessageInputComponent, { className: "MessageInputComponent", filePath: "src/lib/components/message/message-input.component.ts", lineNumber: 44 }); })();
1615
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MessageInputComponent, { className: "MessageInputComponent", filePath: "src/lib/components/message/message-input.component.ts", lineNumber: 25 }); })();
1625
1616
  //# sourceMappingURL=message-input.component.js.map