@memberjunction/ng-conversations 5.22.0 → 5.24.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 (115) hide show
  1. package/README.md +20 -0
  2. package/dist/lib/components/artifact/artifact-share-modal.component.d.ts.map +1 -1
  3. package/dist/lib/components/artifact/artifact-share-modal.component.js +58 -60
  4. package/dist/lib/components/artifact/artifact-share-modal.component.js.map +1 -1
  5. package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts.map +1 -1
  6. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js +31 -32
  7. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js.map +1 -1
  8. package/dist/lib/components/collection/artifact-create-modal.component.d.ts +1 -0
  9. package/dist/lib/components/collection/artifact-create-modal.component.d.ts.map +1 -1
  10. package/dist/lib/components/collection/artifact-create-modal.component.js +81 -63
  11. package/dist/lib/components/collection/artifact-create-modal.component.js.map +1 -1
  12. package/dist/lib/components/collection/collection-artifact-card.component.js +7 -6
  13. package/dist/lib/components/collection/collection-artifact-card.component.js.map +1 -1
  14. package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
  15. package/dist/lib/components/collection/collection-form-modal.component.js +22 -22
  16. package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
  17. package/dist/lib/components/collection/collection-share-modal.component.d.ts.map +1 -1
  18. package/dist/lib/components/collection/collection-share-modal.component.js +65 -67
  19. package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
  20. package/dist/lib/components/collection/collection-view.component.js +71 -59
  21. package/dist/lib/components/collection/collection-view.component.js.map +1 -1
  22. package/dist/lib/components/collection/collections-full-view.component.js +7 -8
  23. package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
  24. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +25 -28
  25. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  26. package/dist/lib/components/conversation/conversation-chat-area.component.js +478 -572
  27. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  28. package/dist/lib/components/conversation/conversation-empty-state.component.d.ts +7 -1
  29. package/dist/lib/components/conversation/conversation-empty-state.component.d.ts.map +1 -1
  30. package/dist/lib/components/conversation/conversation-empty-state.component.js +101 -52
  31. package/dist/lib/components/conversation/conversation-empty-state.component.js.map +1 -1
  32. package/dist/lib/components/conversation/conversation-list.component.d.ts +3 -3
  33. package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
  34. package/dist/lib/components/conversation/conversation-list.component.js +44 -30
  35. package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
  36. package/dist/lib/components/dialogs/input-dialog.component.d.ts +0 -3
  37. package/dist/lib/components/dialogs/input-dialog.component.d.ts.map +1 -1
  38. package/dist/lib/components/dialogs/input-dialog.component.js +12 -17
  39. package/dist/lib/components/dialogs/input-dialog.component.js.map +1 -1
  40. package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
  41. package/dist/lib/components/export/export-modal.component.js +23 -23
  42. package/dist/lib/components/export/export-modal.component.js.map +1 -1
  43. package/dist/lib/components/members/members-modal.component.d.ts.map +1 -1
  44. package/dist/lib/components/members/members-modal.component.js +96 -85
  45. package/dist/lib/components/members/members-modal.component.js.map +1 -1
  46. package/dist/lib/components/message/actionable-commands.component.d.ts +2 -2
  47. package/dist/lib/components/message/actionable-commands.component.d.ts.map +1 -1
  48. package/dist/lib/components/message/actionable-commands.component.js +9 -10
  49. package/dist/lib/components/message/actionable-commands.component.js.map +1 -1
  50. package/dist/lib/components/message/conversation-message-rating.component.d.ts +1 -1
  51. package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
  52. package/dist/lib/components/message/conversation-message-rating.component.js +1 -1
  53. package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
  54. package/dist/lib/components/message/message-input.component.d.ts +23 -5
  55. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  56. package/dist/lib/components/message/message-input.component.js +72 -29
  57. package/dist/lib/components/message/message-input.component.js.map +1 -1
  58. package/dist/lib/components/message/message-item.component.d.ts +14 -2
  59. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  60. package/dist/lib/components/message/message-item.component.js +31 -28
  61. package/dist/lib/components/message/message-item.component.js.map +1 -1
  62. package/dist/lib/components/message/message-list.component.d.ts +1 -2
  63. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  64. package/dist/lib/components/message/message-list.component.js +1 -1
  65. package/dist/lib/components/message/message-list.component.js.map +1 -1
  66. package/dist/lib/components/overlay/chat-overlay.component.d.ts +157 -0
  67. package/dist/lib/components/overlay/chat-overlay.component.d.ts.map +1 -0
  68. package/dist/lib/components/overlay/chat-overlay.component.js +462 -0
  69. package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -0
  70. package/dist/lib/components/project/project-form-modal.component.d.ts +2 -2
  71. package/dist/lib/components/project/project-form-modal.component.d.ts.map +1 -1
  72. package/dist/lib/components/project/project-form-modal.component.js +24 -28
  73. package/dist/lib/components/project/project-form-modal.component.js.map +1 -1
  74. package/dist/lib/components/project/project-selector.component.d.ts +4 -3
  75. package/dist/lib/components/project/project-selector.component.d.ts.map +1 -1
  76. package/dist/lib/components/project/project-selector.component.js +78 -115
  77. package/dist/lib/components/project/project-selector.component.js.map +1 -1
  78. package/dist/lib/components/search/search-panel.component.js +84 -84
  79. package/dist/lib/components/search/search-panel.component.js.map +1 -1
  80. package/dist/lib/components/share/share-modal.component.d.ts.map +1 -1
  81. package/dist/lib/components/share/share-modal.component.js +77 -68
  82. package/dist/lib/components/share/share-modal.component.js.map +1 -1
  83. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +2 -3
  84. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  85. package/dist/lib/components/workspace/conversation-workspace.component.js +29 -32
  86. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  87. package/dist/lib/conversations.module.d.ts +19 -26
  88. package/dist/lib/conversations.module.d.ts.map +1 -1
  89. package/dist/lib/conversations.module.js +20 -43
  90. package/dist/lib/conversations.module.js.map +1 -1
  91. package/dist/lib/services/active-tasks.service.d.ts +1 -3
  92. package/dist/lib/services/active-tasks.service.d.ts.map +1 -1
  93. package/dist/lib/services/active-tasks.service.js +6 -9
  94. package/dist/lib/services/active-tasks.service.js.map +1 -1
  95. package/dist/lib/services/conversation-agent.service.d.ts +9 -4
  96. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  97. package/dist/lib/services/conversation-agent.service.js +83 -61
  98. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  99. package/dist/lib/services/dialog.service.d.ts +6 -6
  100. package/dist/lib/services/dialog.service.d.ts.map +1 -1
  101. package/dist/lib/services/dialog.service.js +26 -23
  102. package/dist/lib/services/dialog.service.js.map +1 -1
  103. package/dist/public-api.d.ts +1 -2
  104. package/dist/public-api.d.ts.map +1 -1
  105. package/dist/public-api.js +1 -2
  106. package/dist/public-api.js.map +1 -1
  107. package/package.json +21 -27
  108. package/dist/lib/models/conversation-complete-query.model.d.ts +0 -95
  109. package/dist/lib/models/conversation-complete-query.model.d.ts.map +0 -1
  110. package/dist/lib/models/conversation-complete-query.model.js +0 -22
  111. package/dist/lib/models/conversation-complete-query.model.js.map +0 -1
  112. package/dist/lib/services/conversation-data.service.d.ts +0 -134
  113. package/dist/lib/services/conversation-data.service.d.ts.map +0 -1
  114. package/dist/lib/services/conversation-data.service.js +0 -287
  115. package/dist/lib/services/conversation-data.service.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-message-rating.component.js","sourceRoot":"","sources":["../../../../src/lib/components/message/conversation-message-rating.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, OnInit, ChangeDetectorRef } from '@angular/core';\nimport { Metadata, RunView, UserInfo } from '@memberjunction/core';\nimport { MJConversationDetailRatingEntity } from '@memberjunction/core-entities';\nimport { RatingJSON } from '../../models/conversation-complete-query.model';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Component for displaying and managing multi-user ratings on conversation messages.\n * Shows aggregate ratings and allows users to provide their own rating.\n * Uses optimistic updates — UI reflects the change immediately while DB saves in background.\n */\n@Component({\n standalone: false,\n selector: 'mj-conversation-message-rating',\n template: `\n <div class=\"rating-container\">\n @if (totalRatings > 0) {\n <div class=\"aggregate-rating\" [title]=\"getRatingsTooltip()\">\n <span class=\"thumbs-up\" [class.has-votes]=\"thumbsUpCount > 0\">\n 👍 {{ thumbsUpCount }}\n </span>\n <span class=\"thumbs-down\" [class.has-votes]=\"thumbsDownCount > 0\">\n 👎 {{ thumbsDownCount }}\n </span>\n <span class=\"total-count\">({{ totalRatings }} {{ totalRatings === 1 ? 'rating' : 'ratings' }})</span>\n </div>\n }\n\n <div class=\"user-rating\" [class.has-rated]=\"currentUserRating != null\">\n <button\n class=\"rating-button thumbs-up-btn\"\n [class.active]=\"currentUserRating != null && currentUserRating >= 8\"\n [disabled]=\"isSaving\"\n (click)=\"RateThumbsUp()\"\n title=\"This was helpful\"\n type=\"button\">\n 👍\n </button>\n <button\n class=\"rating-button thumbs-down-btn\"\n [class.active]=\"currentUserRating != null && currentUserRating <= 3\"\n [disabled]=\"isSaving\"\n (click)=\"RateThumbsDown()\"\n title=\"This was not helpful\"\n type=\"button\">\n 👎\n </button>\n </div>\n </div>\n `,\n styles: [`\n .rating-container {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n\n .aggregate-rating {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n\n .thumbs-up, .thumbs-down {\n opacity: 0.5;\n }\n\n .thumbs-up.has-votes, .thumbs-down.has-votes {\n opacity: 1;\n }\n\n .total-count {\n font-size: 12px;\n color: var(--mj-text-disabled);\n }\n\n .user-rating {\n display: flex;\n gap: 4px;\n margin-left: auto;\n }\n\n .rating-button {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n padding: 6px 10px;\n cursor: pointer;\n font-size: 16px;\n opacity: 0.6;\n transition: all 0.2s;\n min-width: 36px;\n }\n\n .rating-button:hover:not(:disabled) {\n opacity: 1;\n border-color: var(--mj-text-muted);\n }\n\n .rating-button:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n .rating-button.active {\n opacity: 1;\n }\n\n .thumbs-up-btn {\n color: var(--mj-status-success);\n }\n\n .thumbs-up-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n }\n\n .thumbs-up-btn.active {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n }\n\n .thumbs-down-btn {\n color: var(--mj-status-error);\n }\n\n .thumbs-down-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n }\n\n .thumbs-down-btn.active {\n border-color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n }\n `]\n})\nexport class ConversationMessageRatingComponent implements OnInit {\n @Input() conversationDetailId!: string;\n @Input() currentUser!: UserInfo;\n @Input() ratingsData?: RatingJSON[];\n\n thumbsUpCount = 0;\n thumbsDownCount = 0;\n totalRatings = 0;\n currentUserRating: number | null = null;\n isSaving = false;\n\n private allRatings: RatingJSON[] = [];\n private currentUserRatingId: string | null = null;\n\n private get currentUserId(): string {\n return this.currentUser?.ID || '';\n }\n\n constructor(private cdr: ChangeDetectorRef) {}\n\n async ngOnInit() {\n if (this.ratingsData) {\n this.processRatings(this.ratingsData);\n } else {\n await this.loadRatings();\n }\n }\n\n private processRatings(ratings: RatingJSON[] | MJConversationDetailRatingEntity[]): void {\n this.allRatings = ratings as RatingJSON[];\n this.thumbsUpCount = ratings.filter(r => r.Rating != null && r.Rating >= 8).length;\n this.thumbsDownCount = ratings.filter(r => r.Rating != null && r.Rating <= 3).length;\n this.totalRatings = ratings.length;\n\n const mine = ratings.find(r => UUIDsEqual(r.UserID, this.currentUserId));\n this.currentUserRating = mine?.Rating ?? null;\n this.currentUserRatingId = mine ? (mine as RatingJSON).ID ?? null : null;\n }\n\n getRatingsTooltip(): string {\n if (this.allRatings.length === 0) return '';\n\n const upUsers = this.allRatings\n .filter(r => r.Rating != null && r.Rating >= 8)\n .map(r => (r as RatingJSON).UserName || 'Unknown')\n .join(', ');\n\n const downUsers = this.allRatings\n .filter(r => r.Rating != null && r.Rating <= 3)\n .map(r => (r as RatingJSON).UserName || 'Unknown')\n .join(', ');\n\n const parts: string[] = [];\n if (upUsers) parts.push(`👍 ${upUsers}`);\n if (downUsers) parts.push(`👎 ${downUsers}`);\n return parts.join('\\n');\n }\n\n async RateThumbsUp(): Promise<void> {\n await this.saveRating(10);\n }\n\n async RateThumbsDown(): Promise<void> {\n await this.saveRating(1);\n }\n\n private async loadRatings(): Promise<void> {\n try {\n const rv = new RunView();\n const result = await rv.RunView<MJConversationDetailRatingEntity>({\n EntityName: 'MJ: Conversation Detail Ratings',\n ExtraFilter: `ConversationDetailID='${this.conversationDetailId}'`,\n ResultType: 'entity_object'\n });\n if (result.Success && result.Results) {\n this.processRatings(result.Results);\n this.cdr.detectChanges();\n }\n } catch (error) {\n console.error('Failed to load ratings:', error);\n }\n }\n\n private applyOptimisticUpdate(rating: number): void {\n const wasThumbsUp = this.currentUserRating != null && this.currentUserRating >= 8;\n const wasThumbsDown = this.currentUserRating != null && this.currentUserRating <= 3;\n\n // Adjust counts when switching from an existing rating\n if (wasThumbsUp) this.thumbsUpCount--;\n if (wasThumbsDown) this.thumbsDownCount--;\n if (!wasThumbsUp && !wasThumbsDown) this.totalRatings++;\n\n this.currentUserRating = rating;\n if (rating >= 8) this.thumbsUpCount++;\n else this.thumbsDownCount++;\n }\n\n private async saveRating(rating: number): Promise<void> {\n if (this.isSaving) return;\n\n // Ignore if user clicks the same rating they already have\n if (this.currentUserRating === rating) return;\n\n // Snapshot for rollback\n const prevRating = this.currentUserRating;\n const prevRatingId = this.currentUserRatingId;\n const prevThumbsUp = this.thumbsUpCount;\n const prevThumbsDown = this.thumbsDownCount;\n const prevTotal = this.totalRatings;\n\n // Optimistic update — UI reflects change instantly\n this.isSaving = true;\n this.applyOptimisticUpdate(rating);\n this.cdr.detectChanges();\n\n try {\n await this.persistRating(rating, prevRatingId);\n } catch (error) {\n // Roll back to previous state on failure\n console.error('Failed to save rating:', error);\n this.currentUserRating = prevRating;\n this.currentUserRatingId = prevRatingId;\n this.thumbsUpCount = prevThumbsUp;\n this.thumbsDownCount = prevThumbsDown;\n this.totalRatings = prevTotal;\n this.cdr.detectChanges();\n } finally {\n this.isSaving = false;\n this.cdr.detectChanges();\n }\n }\n\n private async persistRating(rating: number, prevRatingId: string | null): Promise<void> {\n if (prevRatingId) {\n // Update existing rating (switch thumbs up ↔ down)\n const md = new Metadata();\n const entity = await md.GetEntityObject<MJConversationDetailRatingEntity>('MJ: Conversation Detail Ratings');\n const loaded = await entity.Load(prevRatingId);\n if (loaded) {\n entity.Rating = rating;\n await entity.Save();\n }\n } else {\n // Create new rating\n const md = new Metadata();\n const entity = await md.GetEntityObject<MJConversationDetailRatingEntity>('MJ: Conversation Detail Ratings');\n entity.ConversationDetailID = this.conversationDetailId;\n entity.UserID = this.currentUserId;\n entity.Rating = rating;\n await entity.Save();\n this.currentUserRatingId = entity.ID;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"conversation-message-rating.component.js","sourceRoot":"","sources":["../../../../src/lib/components/message/conversation-message-rating.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, OnInit, ChangeDetectorRef } from '@angular/core';\nimport { Metadata, RunView, UserInfo } from '@memberjunction/core';\nimport { MJConversationDetailRatingEntity, RatingJSON } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Component for displaying and managing multi-user ratings on conversation messages.\n * Shows aggregate ratings and allows users to provide their own rating.\n * Uses optimistic updates — UI reflects the change immediately while DB saves in background.\n */\n@Component({\n standalone: false,\n selector: 'mj-conversation-message-rating',\n template: `\n <div class=\"rating-container\">\n @if (totalRatings > 0) {\n <div class=\"aggregate-rating\" [title]=\"getRatingsTooltip()\">\n <span class=\"thumbs-up\" [class.has-votes]=\"thumbsUpCount > 0\">\n 👍 {{ thumbsUpCount }}\n </span>\n <span class=\"thumbs-down\" [class.has-votes]=\"thumbsDownCount > 0\">\n 👎 {{ thumbsDownCount }}\n </span>\n <span class=\"total-count\">({{ totalRatings }} {{ totalRatings === 1 ? 'rating' : 'ratings' }})</span>\n </div>\n }\n\n <div class=\"user-rating\" [class.has-rated]=\"currentUserRating != null\">\n <button\n class=\"rating-button thumbs-up-btn\"\n [class.active]=\"currentUserRating != null && currentUserRating >= 8\"\n [disabled]=\"isSaving\"\n (click)=\"RateThumbsUp()\"\n title=\"This was helpful\"\n type=\"button\">\n 👍\n </button>\n <button\n class=\"rating-button thumbs-down-btn\"\n [class.active]=\"currentUserRating != null && currentUserRating <= 3\"\n [disabled]=\"isSaving\"\n (click)=\"RateThumbsDown()\"\n title=\"This was not helpful\"\n type=\"button\">\n 👎\n </button>\n </div>\n </div>\n `,\n styles: [`\n .rating-container {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n\n .aggregate-rating {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n\n .thumbs-up, .thumbs-down {\n opacity: 0.5;\n }\n\n .thumbs-up.has-votes, .thumbs-down.has-votes {\n opacity: 1;\n }\n\n .total-count {\n font-size: 12px;\n color: var(--mj-text-disabled);\n }\n\n .user-rating {\n display: flex;\n gap: 4px;\n margin-left: auto;\n }\n\n .rating-button {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n padding: 6px 10px;\n cursor: pointer;\n font-size: 16px;\n opacity: 0.6;\n transition: all 0.2s;\n min-width: 36px;\n }\n\n .rating-button:hover:not(:disabled) {\n opacity: 1;\n border-color: var(--mj-text-muted);\n }\n\n .rating-button:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n .rating-button.active {\n opacity: 1;\n }\n\n .thumbs-up-btn {\n color: var(--mj-status-success);\n }\n\n .thumbs-up-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n }\n\n .thumbs-up-btn.active {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n }\n\n .thumbs-down-btn {\n color: var(--mj-status-error);\n }\n\n .thumbs-down-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n }\n\n .thumbs-down-btn.active {\n border-color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n }\n `]\n})\nexport class ConversationMessageRatingComponent implements OnInit {\n @Input() conversationDetailId!: string;\n @Input() currentUser!: UserInfo;\n @Input() ratingsData?: RatingJSON[];\n\n thumbsUpCount = 0;\n thumbsDownCount = 0;\n totalRatings = 0;\n currentUserRating: number | null = null;\n isSaving = false;\n\n private allRatings: RatingJSON[] = [];\n private currentUserRatingId: string | null = null;\n\n private get currentUserId(): string {\n return this.currentUser?.ID || '';\n }\n\n constructor(private cdr: ChangeDetectorRef) {}\n\n async ngOnInit() {\n if (this.ratingsData) {\n this.processRatings(this.ratingsData);\n } else {\n await this.loadRatings();\n }\n }\n\n private processRatings(ratings: RatingJSON[] | MJConversationDetailRatingEntity[]): void {\n this.allRatings = ratings as RatingJSON[];\n this.thumbsUpCount = ratings.filter(r => r.Rating != null && r.Rating >= 8).length;\n this.thumbsDownCount = ratings.filter(r => r.Rating != null && r.Rating <= 3).length;\n this.totalRatings = ratings.length;\n\n const mine = ratings.find(r => UUIDsEqual(r.UserID, this.currentUserId));\n this.currentUserRating = mine?.Rating ?? null;\n this.currentUserRatingId = mine ? (mine as RatingJSON).ID ?? null : null;\n }\n\n getRatingsTooltip(): string {\n if (this.allRatings.length === 0) return '';\n\n const upUsers = this.allRatings\n .filter(r => r.Rating != null && r.Rating >= 8)\n .map(r => (r as RatingJSON).UserName || 'Unknown')\n .join(', ');\n\n const downUsers = this.allRatings\n .filter(r => r.Rating != null && r.Rating <= 3)\n .map(r => (r as RatingJSON).UserName || 'Unknown')\n .join(', ');\n\n const parts: string[] = [];\n if (upUsers) parts.push(`👍 ${upUsers}`);\n if (downUsers) parts.push(`👎 ${downUsers}`);\n return parts.join('\\n');\n }\n\n async RateThumbsUp(): Promise<void> {\n await this.saveRating(10);\n }\n\n async RateThumbsDown(): Promise<void> {\n await this.saveRating(1);\n }\n\n private async loadRatings(): Promise<void> {\n try {\n const rv = new RunView();\n const result = await rv.RunView<MJConversationDetailRatingEntity>({\n EntityName: 'MJ: Conversation Detail Ratings',\n ExtraFilter: `ConversationDetailID='${this.conversationDetailId}'`,\n ResultType: 'entity_object'\n });\n if (result.Success && result.Results) {\n this.processRatings(result.Results);\n this.cdr.detectChanges();\n }\n } catch (error) {\n console.error('Failed to load ratings:', error);\n }\n }\n\n private applyOptimisticUpdate(rating: number): void {\n const wasThumbsUp = this.currentUserRating != null && this.currentUserRating >= 8;\n const wasThumbsDown = this.currentUserRating != null && this.currentUserRating <= 3;\n\n // Adjust counts when switching from an existing rating\n if (wasThumbsUp) this.thumbsUpCount--;\n if (wasThumbsDown) this.thumbsDownCount--;\n if (!wasThumbsUp && !wasThumbsDown) this.totalRatings++;\n\n this.currentUserRating = rating;\n if (rating >= 8) this.thumbsUpCount++;\n else this.thumbsDownCount++;\n }\n\n private async saveRating(rating: number): Promise<void> {\n if (this.isSaving) return;\n\n // Ignore if user clicks the same rating they already have\n if (this.currentUserRating === rating) return;\n\n // Snapshot for rollback\n const prevRating = this.currentUserRating;\n const prevRatingId = this.currentUserRatingId;\n const prevThumbsUp = this.thumbsUpCount;\n const prevThumbsDown = this.thumbsDownCount;\n const prevTotal = this.totalRatings;\n\n // Optimistic update — UI reflects change instantly\n this.isSaving = true;\n this.applyOptimisticUpdate(rating);\n this.cdr.detectChanges();\n\n try {\n await this.persistRating(rating, prevRatingId);\n } catch (error) {\n // Roll back to previous state on failure\n console.error('Failed to save rating:', error);\n this.currentUserRating = prevRating;\n this.currentUserRatingId = prevRatingId;\n this.thumbsUpCount = prevThumbsUp;\n this.thumbsDownCount = prevThumbsDown;\n this.totalRatings = prevTotal;\n this.cdr.detectChanges();\n } finally {\n this.isSaving = false;\n this.cdr.detectChanges();\n }\n }\n\n private async persistRating(rating: number, prevRatingId: string | null): Promise<void> {\n if (prevRatingId) {\n // Update existing rating (switch thumbs up ↔ down)\n const md = new Metadata();\n const entity = await md.GetEntityObject<MJConversationDetailRatingEntity>('MJ: Conversation Detail Ratings');\n const loaded = await entity.Load(prevRatingId);\n if (loaded) {\n entity.Rating = rating;\n await entity.Save();\n }\n } else {\n // Create new rating\n const md = new Metadata();\n const entity = await md.GetEntityObject<MJConversationDetailRatingEntity>('MJ: Conversation Detail Ratings');\n entity.ConversationDetailID = this.conversationDetailId;\n entity.UserID = this.currentUserId;\n entity.Rating = rating;\n await entity.Save();\n this.currentUserRatingId = entity.ID;\n }\n }\n}\n"]}
@@ -5,7 +5,6 @@ import { MJAIAgentEntityExtended, MJAIAgentRunEntityExtended } from "@memberjunc
5
5
  import { DialogService } from '../../services/dialog.service';
6
6
  import { ToastService } from '../../services/toast.service';
7
7
  import { ConversationAgentService } from '../../services/conversation-agent.service';
8
- import { ConversationDataService } from '../../services/conversation-data.service';
9
8
  import { DataCacheService } from '../../services/data-cache.service';
10
9
  import { ActiveTasksService } from '../../services/active-tasks.service';
11
10
  import { ConversationStreamingService } from '../../services/conversation-streaming.service';
@@ -15,19 +14,20 @@ import { MentionParserService } from '../../services/mention-parser.service';
15
14
  import { ConversationAttachmentService } from '../../services/conversation-attachment.service';
16
15
  import { PendingAttachment } from '../mention/mention-editor.component';
17
16
  import { LazyArtifactInfo } from '../../models/lazy-artifact-info';
17
+ import { ConversationBridgeService } from '../../services/conversation-bridge.service';
18
18
  import { MessageInputBoxComponent } from './message-input-box.component';
19
19
  import * as i0 from "@angular/core";
20
20
  export declare class MessageInputComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit {
21
21
  private dialogService;
22
22
  private toastService;
23
23
  private agentService;
24
- private conversationData;
25
24
  private dataCache;
26
25
  private activeTasks;
27
26
  private streamingService;
28
27
  private mentionParser;
29
28
  private mentionAutocomplete;
30
29
  private attachmentService;
30
+ private bridge;
31
31
  private readonly JSON_ARTIFACT_TYPE_ID;
32
32
  conversationId: string;
33
33
  conversationName?: string | null;
@@ -43,6 +43,7 @@ export declare class MessageInputComponent implements OnInit, OnDestroy, OnChang
43
43
  systemArtifactsByDetailId?: Map<string, LazyArtifactInfo[]>;
44
44
  agentRunsByDetailId?: Map<string, MJAIAgentRunEntityExtended>;
45
45
  emptyStateMode: boolean;
46
+ appContext: Record<string, unknown> | null;
46
47
  private _initialMessage;
47
48
  private _initialAttachments;
48
49
  private _isComponentReady;
@@ -107,7 +108,8 @@ export declare class MessageInputComponent implements OnInit, OnDestroy, OnChang
107
108
  private completionTimestamps;
108
109
  private registeredCallbacks;
109
110
  private pendingAttachments;
110
- constructor(dialogService: DialogService, toastService: ToastService, agentService: ConversationAgentService, conversationData: ConversationDataService, dataCache: DataCacheService, activeTasks: ActiveTasksService, streamingService: ConversationStreamingService, mentionParser: MentionParserService, mentionAutocomplete: MentionAutocompleteService, attachmentService: ConversationAttachmentService);
111
+ private engine;
112
+ constructor(dialogService: DialogService, toastService: ToastService, agentService: ConversationAgentService, dataCache: DataCacheService, activeTasks: ActiveTasksService, streamingService: ConversationStreamingService, mentionParser: MentionParserService, mentionAutocomplete: MentionAutocompleteService, attachmentService: ConversationAttachmentService, bridge: ConversationBridgeService);
111
113
  ngOnInit(): Promise<void>;
112
114
  ngOnChanges(changes: SimpleChanges): void;
113
115
  ngAfterViewInit(): void;
@@ -186,7 +188,23 @@ export declare class MessageInputComponent implements OnInit, OnDestroy, OnChang
186
188
  */
187
189
  private handleDirectMention;
188
190
  /**
189
- * Handles routing when there's a previous agent - checks intent first
191
+ * Handles routing when there's a previous non-Sage agent in the conversation.
192
+ *
193
+ * LATENCY OPTIMIZATION (PR #2309 / plans/agent-latency-optimization.md — Opt #1):
194
+ * Previously, this method made a separate LLM call via checkContinuityIntent() to decide
195
+ * whether the user's new message was still directed at the previous agent or should be
196
+ * routed to Sage. That call added ~300ms of latency on every message in a conversation
197
+ * with an active agent — the single largest source of non-inference overhead on the client.
198
+ *
199
+ * The heuristic replacement is simple: if a previous non-Sage agent exists, always continue
200
+ * with it. The user can @mention a different agent (or Sage) to explicitly switch. This is
201
+ * more predictable and eliminates a common source of confusion where the intent check
202
+ * incorrectly rerouted messages away from the active agent.
203
+ *
204
+ * The checkContinuityIntent() method and the underlying checkAgentContinuityIntent() service
205
+ * method are preserved (not deleted) so we can reintroduce intent checking in the future
206
+ * when browser-local inference is fast enough (~20-50ms) to do this without blocking the
207
+ * user. See PR #2309 for the full discussion.
190
208
  */
191
209
  private handleAgentContinuity;
192
210
  /**
@@ -302,6 +320,6 @@ export declare class MessageInputComponent implements OnInit, OnDestroy, OnChang
302
320
  */
303
321
  private cleanupCompletionTimestamp;
304
322
  static ɵfac: i0.ɵɵFactoryDeclaration<MessageInputComponent, never>;
305
- static ɵcmp: i0.ɵɵComponentDeclaration<MessageInputComponent, "mj-message-input", never, { "conversationId": { "alias": "conversationId"; "required": false; }; "conversationName": { "alias": "conversationName"; "required": false; }; "currentUser": { "alias": "currentUser"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "parentMessageId": { "alias": "parentMessageId"; "required": false; }; "enableAttachments": { "alias": "enableAttachments"; "required": false; }; "maxAttachments": { "alias": "maxAttachments"; "required": false; }; "maxAttachmentSizeBytes": { "alias": "maxAttachmentSizeBytes"; "required": false; }; "acceptedFileTypes": { "alias": "acceptedFileTypes"; "required": false; }; "artifactsByDetailId": { "alias": "artifactsByDetailId"; "required": false; }; "systemArtifactsByDetailId": { "alias": "systemArtifactsByDetailId"; "required": false; }; "agentRunsByDetailId": { "alias": "agentRunsByDetailId"; "required": false; }; "emptyStateMode": { "alias": "emptyStateMode"; "required": false; }; "initialMessage": { "alias": "initialMessage"; "required": false; }; "initialAttachments": { "alias": "initialAttachments"; "required": false; }; "conversationHistory": { "alias": "conversationHistory"; "required": false; }; "inProgressMessageIds": { "alias": "inProgressMessageIds"; "required": false; }; }, { "messageSent": "messageSent"; "agentResponse": "agentResponse"; "agentRunDetected": "agentRunDetected"; "agentRunUpdate": "agentRunUpdate"; "messageComplete": "messageComplete"; "artifactCreated": "artifactCreated"; "conversationRenamed": "conversationRenamed"; "intentCheckStarted": "intentCheckStarted"; "intentCheckCompleted": "intentCheckCompleted"; "emptyStateSubmit": "emptyStateSubmit"; "uploadStateChanged": "uploadStateChanged"; }, never, never, false, never>;
323
+ static ɵcmp: i0.ɵɵComponentDeclaration<MessageInputComponent, "mj-message-input", never, { "conversationId": { "alias": "conversationId"; "required": false; }; "conversationName": { "alias": "conversationName"; "required": false; }; "currentUser": { "alias": "currentUser"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "parentMessageId": { "alias": "parentMessageId"; "required": false; }; "enableAttachments": { "alias": "enableAttachments"; "required": false; }; "maxAttachments": { "alias": "maxAttachments"; "required": false; }; "maxAttachmentSizeBytes": { "alias": "maxAttachmentSizeBytes"; "required": false; }; "acceptedFileTypes": { "alias": "acceptedFileTypes"; "required": false; }; "artifactsByDetailId": { "alias": "artifactsByDetailId"; "required": false; }; "systemArtifactsByDetailId": { "alias": "systemArtifactsByDetailId"; "required": false; }; "agentRunsByDetailId": { "alias": "agentRunsByDetailId"; "required": false; }; "emptyStateMode": { "alias": "emptyStateMode"; "required": false; }; "appContext": { "alias": "appContext"; "required": false; }; "initialMessage": { "alias": "initialMessage"; "required": false; }; "initialAttachments": { "alias": "initialAttachments"; "required": false; }; "conversationHistory": { "alias": "conversationHistory"; "required": false; }; "inProgressMessageIds": { "alias": "inProgressMessageIds"; "required": false; }; }, { "messageSent": "messageSent"; "agentResponse": "agentResponse"; "agentRunDetected": "agentRunDetected"; "agentRunUpdate": "agentRunUpdate"; "messageComplete": "messageComplete"; "artifactCreated": "artifactCreated"; "conversationRenamed": "conversationRenamed"; "intentCheckStarted": "intentCheckStarted"; "intentCheckCompleted": "intentCheckCompleted"; "emptyStateSubmit": "emptyStateSubmit"; "uploadStateChanged": "uploadStateChanged"; }, never, never, false, never>;
306
324
  }
307
325
  //# sourceMappingURL=message-input.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"message-input.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/message/message-input.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"message-input.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/message/message-input.component.ts"],"names":[],"mappings":"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"}
@@ -1,22 +1,22 @@
1
1
  import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
2
2
  import { Metadata } from '@memberjunction/core';
3
- import { MJEnvironmentEntityExtended } from '@memberjunction/core-entities';
3
+ import { MJEnvironmentEntityExtended, ConversationEngine } from '@memberjunction/core-entities';
4
4
  import { GraphQLDataProvider, GraphQLAIClient } from '@memberjunction/graphql-dataprovider';
5
5
  import { AIEngineBase } from '@memberjunction/ai-engine-base';
6
6
  import { ConversationUtility } from '@memberjunction/ai-core-plus';
7
7
  import { MJNotificationService } from '@memberjunction/ng-notifications';
8
- import { UUIDsEqual } from '@memberjunction/global';
8
+ import { UUIDsEqual, CleanAndParseJSON } from '@memberjunction/global';
9
9
  import * as i0 from "@angular/core";
10
10
  import * as i1 from "../../services/dialog.service";
11
11
  import * as i2 from "../../services/toast.service";
12
12
  import * as i3 from "../../services/conversation-agent.service";
13
- import * as i4 from "../../services/conversation-data.service";
14
- import * as i5 from "../../services/data-cache.service";
15
- import * as i6 from "../../services/active-tasks.service";
16
- import * as i7 from "../../services/conversation-streaming.service";
17
- import * as i8 from "../../services/mention-parser.service";
18
- import * as i9 from "../../services/mention-autocomplete.service";
19
- import * as i10 from "../../services/conversation-attachment.service";
13
+ import * as i4 from "../../services/data-cache.service";
14
+ import * as i5 from "../../services/active-tasks.service";
15
+ import * as i6 from "../../services/conversation-streaming.service";
16
+ import * as i7 from "../../services/mention-parser.service";
17
+ import * as i8 from "../../services/mention-autocomplete.service";
18
+ import * as i9 from "../../services/conversation-attachment.service";
19
+ import * as i10 from "../../services/conversation-bridge.service";
20
20
  import * as i11 from "./message-input-box.component";
21
21
  const _c0 = ["inputBox"];
22
22
  function MessageInputComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
@@ -34,13 +34,13 @@ export class MessageInputComponent {
34
34
  dialogService;
35
35
  toastService;
36
36
  agentService;
37
- conversationData;
38
37
  dataCache;
39
38
  activeTasks;
40
39
  streamingService;
41
40
  mentionParser;
42
41
  mentionAutocomplete;
43
42
  attachmentService;
43
+ bridge;
44
44
  // Default artifact type ID for JSON (when agent doesn't specify DefaultArtifactTypeID)
45
45
  JSON_ARTIFACT_TYPE_ID = 'ae674c7e-ea0d-49ea-89e4-0649f5eb20d4';
46
46
  conversationId;
@@ -57,6 +57,7 @@ export class MessageInputComponent {
57
57
  systemArtifactsByDetailId; // Pre-loaded system artifact data (Visibility='System Only')
58
58
  agentRunsByDetailId; // Pre-loaded agent run data for performance
59
59
  emptyStateMode = false; // When true, emits emptyStateSubmit instead of creating messages directly
60
+ appContext = null; // Application context for AI agent awareness
60
61
  // Initial message to send automatically - using getter/setter for precise control
61
62
  _initialMessage = null;
62
63
  _initialAttachments = null;
@@ -130,17 +131,18 @@ export class MessageInputComponent {
130
131
  registeredCallbacks = new Map();
131
132
  // Track pending attachments from the input box
132
133
  pendingAttachments = [];
133
- constructor(dialogService, toastService, agentService, conversationData, dataCache, activeTasks, streamingService, mentionParser, mentionAutocomplete, attachmentService) {
134
+ engine = ConversationEngine.Instance;
135
+ constructor(dialogService, toastService, agentService, dataCache, activeTasks, streamingService, mentionParser, mentionAutocomplete, attachmentService, bridge) {
134
136
  this.dialogService = dialogService;
135
137
  this.toastService = toastService;
136
138
  this.agentService = agentService;
137
- this.conversationData = conversationData;
138
139
  this.dataCache = dataCache;
139
140
  this.activeTasks = activeTasks;
140
141
  this.streamingService = streamingService;
141
142
  this.mentionParser = mentionParser;
142
143
  this.mentionAutocomplete = mentionAutocomplete;
143
144
  this.attachmentService = attachmentService;
145
+ this.bridge = bridge;
144
146
  }
145
147
  async ngOnInit() {
146
148
  this.converationManagerAgent = await this.agentService.getConversationManagerAgent();
@@ -539,16 +541,49 @@ export class MessageInputComponent {
539
541
  await this.executeRouteWithNaming(() => this.invokeAgentDirectly(messageDetail, agentMention, this.conversationId), messageDetail.Message, isFirstMessage);
540
542
  }
541
543
  /**
542
- * Handles routing when there's a previous agent - checks intent first
544
+ * Handles routing when there's a previous non-Sage agent in the conversation.
545
+ *
546
+ * LATENCY OPTIMIZATION (PR #2309 / plans/agent-latency-optimization.md — Opt #1):
547
+ * Previously, this method made a separate LLM call via checkContinuityIntent() to decide
548
+ * whether the user's new message was still directed at the previous agent or should be
549
+ * routed to Sage. That call added ~300ms of latency on every message in a conversation
550
+ * with an active agent — the single largest source of non-inference overhead on the client.
551
+ *
552
+ * The heuristic replacement is simple: if a previous non-Sage agent exists, always continue
553
+ * with it. The user can @mention a different agent (or Sage) to explicitly switch. This is
554
+ * more predictable and eliminates a common source of confusion where the intent check
555
+ * incorrectly rerouted messages away from the active agent.
556
+ *
557
+ * The checkContinuityIntent() method and the underlying checkAgentContinuityIntent() service
558
+ * method are preserved (not deleted) so we can reintroduce intent checking in the future
559
+ * when browser-local inference is fast enough (~20-50ms) to do this without blocking the
560
+ * user. See PR #2309 for the full discussion.
543
561
  */
544
562
  async handleAgentContinuity(messageDetail, lastAgentId, mentionResult, isFirstMessage) {
545
- const intentResult = await this.checkContinuityIntent(lastAgentId, messageDetail.Message);
546
- if (intentResult.decision === 'YES') {
547
- await this.executeRouteWithNaming(() => this.continueWithAgent(messageDetail, lastAgentId, this.conversationId, intentResult.targetArtifactVersionId), messageDetail.Message, isFirstMessage);
548
- }
549
- else {
550
- await this.executeRouteWithNaming(() => this.processMessageThroughAgent(messageDetail, mentionResult), messageDetail.Message, isFirstMessage);
551
- }
563
+ // COMMENTED OUT LLM intent check removed for latency optimization (see JSDoc above).
564
+ // const intentResult = await this.checkContinuityIntent(lastAgentId, messageDetail.Message);
565
+ //
566
+ // if (intentResult.decision === 'YES') {
567
+ // await this.executeRouteWithNaming(
568
+ // () => this.continueWithAgent(
569
+ // messageDetail,
570
+ // lastAgentId,
571
+ // this.conversationId,
572
+ // intentResult.targetArtifactVersionId
573
+ // ),
574
+ // messageDetail.Message,
575
+ // isFirstMessage
576
+ // );
577
+ // } else {
578
+ // await this.executeRouteWithNaming(
579
+ // () => this.processMessageThroughAgent(messageDetail, mentionResult),
580
+ // messageDetail.Message,
581
+ // isFirstMessage
582
+ // );
583
+ // }
584
+ // Always continue with the previous agent — user can @mention another agent to switch.
585
+ await this.executeRouteWithNaming(() => this.continueWithAgent(messageDetail, lastAgentId, this.conversationId, undefined // artifact version targeting unavailable without intent check
586
+ ), messageDetail.Message, isFirstMessage);
552
587
  }
553
588
  /**
554
589
  * Handles routing when there's no previous agent context
@@ -752,7 +787,7 @@ export class MessageInputComponent {
752
787
  conversationId: this.conversationId,
753
788
  conversationName: this.conversationName
754
789
  });
755
- const result = await this.agentService.processMessage(conversationId, userMessage, this.conversationHistory, conversationManagerMessage.ID, this.createProgressCallback(conversationManagerMessage, 'Sage'));
790
+ const result = await this.agentService.processMessage(conversationId, userMessage, this.conversationHistory, conversationManagerMessage.ID, this.createProgressCallback(conversationManagerMessage, 'Sage'), this.appContext);
756
791
  // Task will be removed automatically in markMessageComplete()
757
792
  // DO NOT remove here - agent may still be streaming/processing
758
793
  taskId = null; // Clear reference but don't remove from service
@@ -1747,14 +1782,15 @@ export class MessageInputComponent {
1747
1782
  timeoutPromise
1748
1783
  ]);
1749
1784
  if (result && result.success && (result.parsedResult || result.output)) {
1750
- // Use parsedResult if available, otherwise parse output
1785
+ // Use parsedResult if available, otherwise clean and parse output
1786
+ // (CleanAndParseJSON handles markdown code blocks like ```json ... ```)
1751
1787
  const parsed = result.parsedResult ||
1752
- (result.output ? JSON.parse(result.output) : null);
1788
+ (result.output ? CleanAndParseJSON(result.output) : null);
1753
1789
  if (parsed) {
1754
1790
  const { name, description } = parsed;
1755
1791
  if (name) {
1756
1792
  // Update the conversation name and description in database AND state immediately
1757
- await this.conversationData.saveConversation(this.conversationId, { Name: name, Description: description || '' }, this.currentUser);
1793
+ await this.engine.SaveConversation(this.conversationId, { Name: name, Description: description || '' }, this.currentUser);
1758
1794
  // Emit event for animation in conversation list
1759
1795
  this.conversationRenamed.emit({
1760
1796
  conversationId: this.conversationId,
@@ -1804,8 +1840,13 @@ export class MessageInputComponent {
1804
1840
  conversationName: task.conversationName
1805
1841
  });
1806
1842
  this.activeTasks.remove(task.id);
1807
- // Show completion notification
1808
- MJNotificationService.Instance?.CreateSimpleNotification(`${task.agentName} completed in ${task.conversationName || 'conversation'}`, 'success', 3000);
1843
+ // Show toast only if the user isn't currently viewing this conversation.
1844
+ // If they're watching, the inline completion is sufficient.
1845
+ const isConvoVisible = UUIDsEqual(this.bridge.ActiveConversationID$.value, task.conversationId)
1846
+ && (this.bridge.OverlayActive$.value || this.bridge.WorkspaceActive$.value);
1847
+ if (!isConvoVisible) {
1848
+ MJNotificationService.Instance?.CreateSimpleNotification(`${task.agentName} completed in ${task.conversationName || 'conversation'}`, 'success', 3000);
1849
+ }
1809
1850
  }
1810
1851
  else {
1811
1852
  console.warn(`⚠️ No task found for completed message ${conversationDetail.ID} - task may have been removed prematurely or not added`);
@@ -1825,13 +1866,13 @@ export class MessageInputComponent {
1825
1866
  this.completionTimestamps.delete(conversationDetailId);
1826
1867
  }, 5000); // 5 seconds should be more than enough
1827
1868
  }
1828
- static ɵfac = function MessageInputComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MessageInputComponent)(i0.ɵɵdirectiveInject(i1.DialogService), i0.ɵɵdirectiveInject(i2.ToastService), i0.ɵɵdirectiveInject(i3.ConversationAgentService), i0.ɵɵdirectiveInject(i4.ConversationDataService), i0.ɵɵdirectiveInject(i5.DataCacheService), i0.ɵɵdirectiveInject(i6.ActiveTasksService), i0.ɵɵdirectiveInject(i7.ConversationStreamingService), i0.ɵɵdirectiveInject(i8.MentionParserService), i0.ɵɵdirectiveInject(i9.MentionAutocompleteService), i0.ɵɵdirectiveInject(i10.ConversationAttachmentService)); };
1869
+ static ɵfac = function MessageInputComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MessageInputComponent)(i0.ɵɵdirectiveInject(i1.DialogService), i0.ɵɵdirectiveInject(i2.ToastService), i0.ɵɵdirectiveInject(i3.ConversationAgentService), i0.ɵɵdirectiveInject(i4.DataCacheService), i0.ɵɵdirectiveInject(i5.ActiveTasksService), i0.ɵɵdirectiveInject(i6.ConversationStreamingService), i0.ɵɵdirectiveInject(i7.MentionParserService), i0.ɵɵdirectiveInject(i8.MentionAutocompleteService), i0.ɵɵdirectiveInject(i9.ConversationAttachmentService), i0.ɵɵdirectiveInject(i10.ConversationBridgeService)); };
1829
1870
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MessageInputComponent, selectors: [["mj-message-input"]], viewQuery: function MessageInputComponent_Query(rf, ctx) { if (rf & 1) {
1830
1871
  i0.ɵɵviewQuery(_c0, 5);
1831
1872
  } if (rf & 2) {
1832
1873
  let _t;
1833
1874
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.inputBox = _t.first);
1834
- } }, inputs: { conversationId: "conversationId", conversationName: "conversationName", currentUser: "currentUser", disabled: "disabled", placeholder: "placeholder", parentMessageId: "parentMessageId", enableAttachments: "enableAttachments", maxAttachments: "maxAttachments", maxAttachmentSizeBytes: "maxAttachmentSizeBytes", acceptedFileTypes: "acceptedFileTypes", artifactsByDetailId: "artifactsByDetailId", systemArtifactsByDetailId: "systemArtifactsByDetailId", agentRunsByDetailId: "agentRunsByDetailId", emptyStateMode: "emptyStateMode", initialMessage: "initialMessage", initialAttachments: "initialAttachments", conversationHistory: "conversationHistory", inProgressMessageIds: "inProgressMessageIds" }, outputs: { messageSent: "messageSent", agentResponse: "agentResponse", agentRunDetected: "agentRunDetected", agentRunUpdate: "agentRunUpdate", messageComplete: "messageComplete", artifactCreated: "artifactCreated", conversationRenamed: "conversationRenamed", intentCheckStarted: "intentCheckStarted", intentCheckCompleted: "intentCheckCompleted", emptyStateSubmit: "emptyStateSubmit", uploadStateChanged: "uploadStateChanged" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 4, vars: 12, consts: [["inputBox", ""], [1, "message-input-wrapper"], [1, "processing-indicator"], [3, "valueChange", "textSubmitted", "attachmentsChanged", "attachmentError", "placeholder", "disabled", "showCharacterCount", "enableMentions", "enableAttachments", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes", "currentUser", "rows", "value"], [1, "fas", "fa-circle-notch", "fa-spin"]], template: function MessageInputComponent_Template(rf, ctx) { if (rf & 1) {
1875
+ } }, inputs: { conversationId: "conversationId", conversationName: "conversationName", currentUser: "currentUser", disabled: "disabled", placeholder: "placeholder", parentMessageId: "parentMessageId", enableAttachments: "enableAttachments", maxAttachments: "maxAttachments", maxAttachmentSizeBytes: "maxAttachmentSizeBytes", acceptedFileTypes: "acceptedFileTypes", artifactsByDetailId: "artifactsByDetailId", systemArtifactsByDetailId: "systemArtifactsByDetailId", agentRunsByDetailId: "agentRunsByDetailId", emptyStateMode: "emptyStateMode", appContext: "appContext", initialMessage: "initialMessage", initialAttachments: "initialAttachments", conversationHistory: "conversationHistory", inProgressMessageIds: "inProgressMessageIds" }, outputs: { messageSent: "messageSent", agentResponse: "agentResponse", agentRunDetected: "agentRunDetected", agentRunUpdate: "agentRunUpdate", messageComplete: "messageComplete", artifactCreated: "artifactCreated", conversationRenamed: "conversationRenamed", intentCheckStarted: "intentCheckStarted", intentCheckCompleted: "intentCheckCompleted", emptyStateSubmit: "emptyStateSubmit", uploadStateChanged: "uploadStateChanged" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 4, vars: 12, consts: [["inputBox", ""], [1, "message-input-wrapper"], [1, "processing-indicator"], [3, "valueChange", "textSubmitted", "attachmentsChanged", "attachmentError", "placeholder", "disabled", "showCharacterCount", "enableMentions", "enableAttachments", "maxAttachments", "maxAttachmentSizeBytes", "acceptedFileTypes", "currentUser", "rows", "value"], [1, "fas", "fa-circle-notch", "fa-spin"]], template: function MessageInputComponent_Template(rf, ctx) { if (rf & 1) {
1835
1876
  const _r1 = i0.ɵɵgetCurrentView();
1836
1877
  i0.ɵɵelementStart(0, "div", 1);
1837
1878
  i0.ɵɵconditionalCreate(1, MessageInputComponent_Conditional_1_Template, 4, 1, "div", 2);
@@ -1850,7 +1891,7 @@ export class MessageInputComponent {
1850
1891
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MessageInputComponent, [{
1851
1892
  type: Component,
1852
1893
  args: [{ standalone: false, selector: 'mj-message-input', template: "<div class=\"message-input-wrapper\">\n <!-- Processing Indicator Overlay -->\n @if (isProcessing) {\n <div class=\"processing-indicator\">\n <i class=\"fas fa-circle-notch fa-spin\"></i>\n <span>{{ processingMessage }}</span>\n </div>\n }\n\n <!-- Message Input Box -->\n <mj-message-input-box\n #inputBox\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled || isProcessing\"\n [showCharacterCount]=\"false\"\n [enableMentions]=\"true\"\n [enableAttachments]=\"enableAttachments\"\n [maxAttachments]=\"maxAttachments\"\n [maxAttachmentSizeBytes]=\"maxAttachmentSizeBytes\"\n [acceptedFileTypes]=\"acceptedFileTypes\"\n [currentUser]=\"currentUser\"\n [rows]=\"3\"\n [(value)]=\"messageText\"\n (textSubmitted)=\"onTextSubmitted($event)\"\n (attachmentsChanged)=\"onAttachmentsChanged($event)\"\n (attachmentError)=\"onAttachmentError($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: color-mix(in srgb, var(--mj-bg-surface-card) 95%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n pointer-events: none;\n}\n.processing-indicator i {\n color: var(--mj-brand-primary);\n}\n.processing-indicator span {\n font-size: 0.9rem;\n color: var(--mj-text-primary);\n}\n"] }]
1853
- }], () => [{ type: i1.DialogService }, { type: i2.ToastService }, { type: i3.ConversationAgentService }, { type: i4.ConversationDataService }, { type: i5.DataCacheService }, { type: i6.ActiveTasksService }, { type: i7.ConversationStreamingService }, { type: i8.MentionParserService }, { type: i9.MentionAutocompleteService }, { type: i10.ConversationAttachmentService }], { conversationId: [{
1894
+ }], () => [{ type: i1.DialogService }, { type: i2.ToastService }, { type: i3.ConversationAgentService }, { type: i4.DataCacheService }, { type: i5.ActiveTasksService }, { type: i6.ConversationStreamingService }, { type: i7.MentionParserService }, { type: i8.MentionAutocompleteService }, { type: i9.ConversationAttachmentService }, { type: i10.ConversationBridgeService }], { conversationId: [{
1854
1895
  type: Input
1855
1896
  }], conversationName: [{
1856
1897
  type: Input
@@ -1878,6 +1919,8 @@ export class MessageInputComponent {
1878
1919
  type: Input
1879
1920
  }], emptyStateMode: [{
1880
1921
  type: Input
1922
+ }], appContext: [{
1923
+ type: Input
1881
1924
  }], initialMessage: [{
1882
1925
  type: Input
1883
1926
  }], initialAttachments: [{