@atlaskit/editor-plugin-mentions 14.0.0 → 14.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,14 +10,17 @@ import { MENTION_PROVIDER_REJECTED, MENTION_PROVIDER_UNDEFINED } from '../types'
10
10
  import { mentionPluginKey } from './key';
11
11
  import { canMentionBeCreatedInRange } from './utils';
12
12
  export const ACTIONS = {
13
+ COMMIT_PENDING_TYPED_AGENT_MENTION: 'COMMIT_PENDING_TYPED_AGENT_MENTION',
14
+ SET_PENDING_TYPED_AGENT_MENTION: 'SET_PENDING_TYPED_AGENT_MENTION',
13
15
  SET_PROVIDER: 'SET_PROVIDER'
14
16
  };
15
17
 
16
18
  // 'AGENT' is not in the ADF schema UserType enum but is used at runtime.
17
19
  const AGENT_USER_TYPES = new Set(['APP', 'AGENT']);
18
20
  const AI_STREAMING_TRANSFORMATION_META_KEY = 'isAIStreamingTransformation';
21
+ const AGENT_MENTION_INACTIVITY_MS = 3000;
19
22
  const PACKAGE_NAME = "@atlaskit/editor-plugin-mentions";
20
- const PACKAGE_VERSION = "13.3.15";
23
+ const PACKAGE_VERSION = "14.1.0";
21
24
  const setProvider = provider => (state, dispatch) => {
22
25
  if (dispatch) {
23
26
  dispatch(state.tr.setMeta(mentionPluginKey, {
@@ -29,6 +32,89 @@ const setProvider = provider => (state, dispatch) => {
29
32
  }
30
33
  return true;
31
34
  };
35
+
36
+ /**
37
+ * Returns true when a transaction represents a local user document edit that
38
+ * should restart pending agent-mention inactivity tracking.
39
+ *
40
+ * Remote/collab updates, replace-document transactions, AI streaming transforms,
41
+ * selection-only movements, and metadata-only transactions are intentionally ignored.
42
+ */
43
+ const isQualifyingLocalUserDocChange = tr => {
44
+ const isAIStreaming = Boolean(tr.getMeta(AI_STREAMING_TRANSFORMATION_META_KEY));
45
+ return tr.docChanged && !tr.getMeta('isRemote') && !tr.getMeta('replaceDocument') && !isAIStreaming;
46
+ };
47
+
48
+ /**
49
+ * Reads agent-mention details from a known document position without traversing
50
+ * the document. Callers pass a matcher so mapped positions are only accepted
51
+ * when they still point at the same pending/tracked mention.
52
+ */
53
+ const getAgentMentionDetailsAtPos = (state, pos, matchesMention) => {
54
+ var _parentNode$type$name;
55
+ if (pos < 0 || pos > state.doc.content.size) {
56
+ return null;
57
+ }
58
+ const node = state.doc.nodeAt(pos);
59
+ const mentionSchema = state.schema.nodes.mention;
60
+ if ((node === null || node === void 0 ? void 0 : node.type) !== mentionSchema || !AGENT_USER_TYPES.has(node.attrs.userType) || !matchesMention(node.attrs) || !node.attrs.id) {
61
+ return null;
62
+ }
63
+ const $mentionPos = state.doc.resolve(pos);
64
+ const parentNode = $mentionPos.node($mentionPos.depth);
65
+ return {
66
+ id: node.attrs.id,
67
+ context: parentNode.textContent.trim() || null,
68
+ nodeSize: node.nodeSize,
69
+ parentNodeType: (_parentNode$type$name = parentNode.type.name) !== null && _parentNode$type$name !== void 0 ? _parentNode$type$name : null,
70
+ pos
71
+ };
72
+ };
73
+
74
+ /**
75
+ * Finds an agent mention that survived a document change when the changed-range
76
+ * scan did not find one. Prefers the previously tracked mention ID when present;
77
+ * otherwise returns a surviving agent mention using the existing traversal order.
78
+ */
79
+ const getSurvivingAgentMentionDetails = (state, preferredId) => {
80
+ const mentionSchema = state.schema.nodes.mention;
81
+ let result = null;
82
+ state.doc.descendants((node, pos) => {
83
+ var _result, _result2;
84
+ if (((_result = result) === null || _result === void 0 ? void 0 : _result.id) === preferredId) {
85
+ return false;
86
+ }
87
+ if (node.type !== mentionSchema || !AGENT_USER_TYPES.has(node.attrs.userType) || !node.attrs.id) {
88
+ return true;
89
+ }
90
+ result = getAgentMentionDetailsAtPos(state, pos, attrs => attrs.id === node.attrs.id);
91
+ return ((_result2 = result) === null || _result2 === void 0 ? void 0 : _result2.id) !== preferredId;
92
+ });
93
+ return result;
94
+ };
95
+
96
+ /**
97
+ * Maps a pending typed agent mention through a document-changing transaction and
98
+ * returns the updated pending state. If the mapped position was deleted or no
99
+ * longer points at the same local mention, the pending mention is cleared.
100
+ */
101
+ const getPendingTypedAgentMentionAfterDocChange = (state, tr, pendingTypedAgentMention, {
102
+ resetTimer
103
+ }) => {
104
+ const mappedPos = tr.mapping.mapResult(pendingTypedAgentMention.pos, 1);
105
+ const resetCount = resetTimer ? pendingTypedAgentMention.resetCount + 1 : pendingTypedAgentMention.resetCount;
106
+ if (mappedPos.deleted) {
107
+ return null;
108
+ }
109
+ const pendingMentionDetails = getAgentMentionDetailsAtPos(state, mappedPos.pos, attrs => attrs.localId === pendingTypedAgentMention.localId);
110
+ return pendingMentionDetails ? {
111
+ id: pendingMentionDetails.id,
112
+ localId: pendingTypedAgentMention.localId,
113
+ nodeSize: pendingMentionDetails.nodeSize,
114
+ pos: pendingMentionDetails.pos,
115
+ resetCount
116
+ } : null;
117
+ };
32
118
  export function createMentionPlugin({
33
119
  pmPluginFactoryParams,
34
120
  fireEvent,
@@ -68,32 +154,71 @@ export function createMentionPlugin({
68
154
  action: null,
69
155
  params: null
70
156
  };
71
- let hasNewPluginState = false;
157
+ let hasPublicPluginStateChanged = false;
72
158
  let newPluginState = pluginState;
159
+ const isAgentMentionsExperimentEnabled = editorExperiment('platform_editor_agent_mentions', true);
73
160
  const hasPositionChanged = oldState.selection.from !== newState.selection.from || oldState.selection.to !== newState.selection.to;
74
161
  if (tr.docChanged || tr.selectionSet && hasPositionChanged) {
75
162
  newPluginState = {
76
163
  ...pluginState,
77
164
  canInsertMention: canMentionBeCreatedInRange(newState.selection.from, newState.selection.to)(newState)
78
165
  };
79
- hasNewPluginState = true;
166
+ hasPublicPluginStateChanged = true;
80
167
  }
81
168
  switch (action) {
169
+ case ACTIONS.COMMIT_PENDING_TYPED_AGENT_MENTION:
170
+ {
171
+ var _newPluginState$lastA;
172
+ const pendingTypedAgentMention = newPluginState.pendingTypedAgentMention;
173
+ // Ignore stale timer callbacks. The localId and resetCount must still match the
174
+ // current pending mention so older timers cannot publish after later user edits.
175
+ if (!isAgentMentionsExperimentEnabled || !pendingTypedAgentMention || pendingTypedAgentMention.localId !== (params === null || params === void 0 ? void 0 : params.localId) || pendingTypedAgentMention.resetCount !== (params === null || params === void 0 ? void 0 : params.resetCount)) {
176
+ break;
177
+ }
178
+ const pendingMentionDetails = getAgentMentionDetailsAtPos(newState, pendingTypedAgentMention.pos, attrs => attrs.localId === pendingTypedAgentMention.localId);
179
+ if (!pendingMentionDetails) {
180
+ newPluginState = {
181
+ ...newPluginState,
182
+ pendingTypedAgentMention: null
183
+ };
184
+ break;
185
+ }
186
+ newPluginState = {
187
+ ...newPluginState,
188
+ pendingTypedAgentMention: null,
189
+ lastInsertedAgentMentionId: pendingMentionDetails.id,
190
+ lastInsertedAgentMentionContext: pendingMentionDetails.context,
191
+ lastInsertedAgentMentionParentNodeType: pendingMentionDetails.parentNodeType,
192
+ lastAgentMentionInsertionCount: ((_newPluginState$lastA = newPluginState.lastAgentMentionInsertionCount) !== null && _newPluginState$lastA !== void 0 ? _newPluginState$lastA : 0) + 1
193
+ };
194
+ hasPublicPluginStateChanged = true;
195
+ break;
196
+ }
82
197
  case ACTIONS.SET_PROVIDER:
83
198
  newPluginState = {
84
199
  ...newPluginState,
85
200
  mentionProvider: params.provider
86
201
  };
87
- hasNewPluginState = true;
202
+ hasPublicPluginStateChanged = true;
88
203
  break;
89
204
  }
90
205
 
91
206
  // When the agent mentions experiment is off, dispatch immediately (original behaviour).
92
207
  // When it's on, defer dispatch to after the agent tracking block below so that
93
208
  // agent-mention state changes are included in the notification.
94
- if (hasNewPluginState && !editorExperiment('platform_editor_agent_mentions', true)) {
209
+ if (hasPublicPluginStateChanged && !isAgentMentionsExperimentEnabled) {
95
210
  pmPluginFactoryParams.dispatch(mentionPluginKey, newPluginState);
96
211
  }
212
+ if (isAgentMentionsExperimentEnabled && tr.docChanged && tr.getMeta('replaceDocument')) {
213
+ newPluginState = {
214
+ ...newPluginState,
215
+ pendingTypedAgentMention: null,
216
+ lastInsertedAgentMentionId: null,
217
+ lastInsertedAgentMentionContext: null,
218
+ lastInsertedAgentMentionParentNodeType: null
219
+ };
220
+ hasPublicPluginStateChanged = true;
221
+ }
97
222
  if (options !== null && options !== void 0 && options.handleMentionsChanged && tr.docChanged) {
98
223
  var _insm$session, _insm$session2;
99
224
  (_insm$session = insm.session) === null || _insm$session === void 0 ? void 0 : _insm$session.startFeature('mentionDeletionDetection');
@@ -152,7 +277,7 @@ export function createMentionPlugin({
152
277
  (_insm$session2 = insm.session) === null || _insm$session2 === void 0 ? void 0 : _insm$session2.endFeature('mentionDeletionDetection');
153
278
  }
154
279
  const isAIStreaming = Boolean(tr.getMeta(AI_STREAMING_TRANSFORMATION_META_KEY));
155
- if (tr.docChanged && !tr.getMeta('replaceDocument') && !isAIStreaming && editorExperiment('platform_editor_agent_mentions', true)) {
280
+ if (tr.docChanged && !tr.getMeta('replaceDocument') && !isAIStreaming && isAgentMentionsExperimentEnabled) {
156
281
  const mentionSchema = newState.schema.nodes.mention;
157
282
  const newDocRanges = [];
158
283
  const oldDocRanges = [];
@@ -198,28 +323,36 @@ export function createMentionPlugin({
198
323
  oldDocRanges.push(...stepOldRanges);
199
324
  }
200
325
  });
201
- if (stepsTouchMentions || newPluginState.lastInsertedAgentMentionId) {
202
- var _newPluginState$lastA, _newPluginState$lastI, _newPluginState$lastI2, _newPluginState$lastI3;
326
+ const shouldResolveAgentMentionState = stepsTouchMentions || Boolean(newPluginState.lastInsertedAgentMentionId);
327
+ if (shouldResolveAgentMentionState) {
328
+ var _newPluginState$lastA2, _newPluginState$lastI, _newPluginState$lastI2, _newPluginState$lastI3;
203
329
  let agentMentionId = null;
204
330
  let agentMentionContext = null;
205
331
  let agentMentionParentNodeType = null;
206
332
  let newCount = 0;
207
333
  let oldAgentMentionId = null;
208
334
  let oldCount = 0;
335
+ const pendingTypedAgentMentionDetails = {};
209
336
  if (stepsTouchMentions) {
210
337
  for (const [from, to] of newDocRanges) {
211
338
  const clampedTo = Math.min(to, newState.doc.content.size);
212
339
  if (from >= clampedTo) continue;
213
- newState.doc.nodesBetween(from, clampedTo, (node, _pos, parent) => {
340
+ newState.doc.nodesBetween(from, clampedTo, (node, pos) => {
214
341
  if (node.type !== mentionSchema || !AGENT_USER_TYPES.has(node.attrs.userType)) {
215
342
  return true;
216
343
  }
217
344
  newCount++;
345
+ if (pendingTypedAgentMentionDetails.current === undefined && action === ACTIONS.SET_PENDING_TYPED_AGENT_MENTION && node.attrs.localId === (params === null || params === void 0 ? void 0 : params.localId)) {
346
+ var _getAgentMentionDetai;
347
+ pendingTypedAgentMentionDetails.current = (_getAgentMentionDetai = getAgentMentionDetailsAtPos(newState, pos, attrs => attrs.localId === params.localId)) !== null && _getAgentMentionDetai !== void 0 ? _getAgentMentionDetai : undefined;
348
+ }
218
349
  if (agentMentionId === null && node.attrs.id) {
219
- var _parent$type$name;
220
- agentMentionId = node.attrs.id;
221
- agentMentionParentNodeType = (_parent$type$name = parent === null || parent === void 0 ? void 0 : parent.type.name) !== null && _parent$type$name !== void 0 ? _parent$type$name : null;
222
- agentMentionContext = (parent === null || parent === void 0 ? void 0 : parent.textContent.trim()) || null;
350
+ const agentMentionDetails = getAgentMentionDetailsAtPos(newState, pos, attrs => attrs.id === node.attrs.id);
351
+ if (agentMentionDetails) {
352
+ agentMentionId = agentMentionDetails.id;
353
+ agentMentionContext = agentMentionDetails.context;
354
+ agentMentionParentNodeType = agentMentionDetails.parentNodeType;
355
+ }
223
356
  }
224
357
  return true;
225
358
  });
@@ -243,33 +376,46 @@ export function createMentionPlugin({
243
376
  // When a deletion collapses the new-doc range to a zero-width point, or when
244
377
  // the doc changed but no step covered the tracked mention, the new-doc scan
245
378
  // above finds nothing. Check whether any agent mention survived in the document.
246
- let resolvedFromSurvivor = false;
379
+ let resolvedFromFullDocFallback = false;
247
380
  if (agentMentionId === null && newPluginState.lastInsertedAgentMentionId) {
248
- const prevId = newPluginState.lastInsertedAgentMentionId;
249
- let survivorId = null;
250
- let survivorContext = null;
251
- let survivorParentNodeType = null;
252
- newState.doc.descendants((node, _pos, parent) => {
253
- if (survivorId === prevId) return false;
254
- if (node.type === mentionSchema && AGENT_USER_TYPES.has(node.attrs.userType)) {
255
- var _parent$type$name2;
256
- // Prefer the previously tracked ID; otherwise keep the first found.
257
- survivorId = node.attrs.id;
258
- survivorParentNodeType = (_parent$type$name2 = parent === null || parent === void 0 ? void 0 : parent.type.name) !== null && _parent$type$name2 !== void 0 ? _parent$type$name2 : null;
259
- survivorContext = (parent === null || parent === void 0 ? void 0 : parent.textContent.trim()) || null;
260
- }
261
- return survivorId !== prevId;
262
- });
263
- if (survivorId !== null) {
264
- agentMentionId = survivorId;
265
- agentMentionContext = survivorContext;
266
- agentMentionParentNodeType = survivorParentNodeType;
267
- resolvedFromSurvivor = true;
381
+ const survivorDetails = getSurvivingAgentMentionDetails(newState, newPluginState.lastInsertedAgentMentionId);
382
+ if (survivorDetails) {
383
+ agentMentionId = survivorDetails.id;
384
+ agentMentionContext = survivorDetails.context;
385
+ agentMentionParentNodeType = survivorDetails.parentNodeType;
386
+ resolvedFromFullDocFallback = true;
268
387
  }
269
388
  }
270
- const isNewInsertion = agentMentionId !== null && !resolvedFromSurvivor && (oldAgentMentionId !== agentMentionId || newCount > oldCount);
271
- const newInsertionCount = isNewInsertion ? ((_newPluginState$lastA = newPluginState.lastAgentMentionInsertionCount) !== null && _newPluginState$lastA !== void 0 ? _newPluginState$lastA : 0) + 1 : undefined;
272
- if (agentMentionId !== ((_newPluginState$lastI = newPluginState.lastInsertedAgentMentionId) !== null && _newPluginState$lastI !== void 0 ? _newPluginState$lastI : null) || agentMentionContext !== ((_newPluginState$lastI2 = newPluginState.lastInsertedAgentMentionContext) !== null && _newPluginState$lastI2 !== void 0 ? _newPluginState$lastI2 : null) || agentMentionParentNodeType !== ((_newPluginState$lastI3 = newPluginState.lastInsertedAgentMentionParentNodeType) !== null && _newPluginState$lastI3 !== void 0 ? _newPluginState$lastI3 : null) || newInsertionCount !== undefined) {
389
+ const isNewInsertion = agentMentionId !== null && !resolvedFromFullDocFallback && (oldAgentMentionId !== agentMentionId || newCount > oldCount);
390
+ const isPendingTypedAgentMentionInsertion = isNewInsertion && action === ACTIONS.SET_PENDING_TYPED_AGENT_MENTION && typeof (params === null || params === void 0 ? void 0 : params.localId) === 'string';
391
+ const newInsertionCount = isNewInsertion ? ((_newPluginState$lastA2 = newPluginState.lastAgentMentionInsertionCount) !== null && _newPluginState$lastA2 !== void 0 ? _newPluginState$lastA2 : 0) + 1 : undefined;
392
+ if (isPendingTypedAgentMentionInsertion && pendingTypedAgentMentionDetails.current) {
393
+ const pendingTypedAgentMentionLocalId = params === null || params === void 0 ? void 0 : params.localId;
394
+ newPluginState = {
395
+ ...newPluginState,
396
+ pendingTypedAgentMention: {
397
+ id: pendingTypedAgentMentionDetails.current.id,
398
+ localId: pendingTypedAgentMentionLocalId,
399
+ nodeSize: pendingTypedAgentMentionDetails.current.nodeSize,
400
+ pos: pendingTypedAgentMentionDetails.current.pos,
401
+ resetCount: 1
402
+ }
403
+ };
404
+ } else if (isPendingTypedAgentMentionInsertion) {
405
+ // Fallback: if the localId-specific scan missed the typed mention,
406
+ // publish immediately so the insertion is not dropped.
407
+ newPluginState = {
408
+ ...newPluginState,
409
+ pendingTypedAgentMention: null,
410
+ lastInsertedAgentMentionId: agentMentionId,
411
+ lastInsertedAgentMentionContext: agentMentionContext,
412
+ lastInsertedAgentMentionParentNodeType: agentMentionParentNodeType,
413
+ ...(newInsertionCount !== undefined ? {
414
+ lastAgentMentionInsertionCount: newInsertionCount
415
+ } : {})
416
+ };
417
+ hasPublicPluginStateChanged = true;
418
+ } else if (agentMentionId !== ((_newPluginState$lastI = newPluginState.lastInsertedAgentMentionId) !== null && _newPluginState$lastI !== void 0 ? _newPluginState$lastI : null) || agentMentionContext !== ((_newPluginState$lastI2 = newPluginState.lastInsertedAgentMentionContext) !== null && _newPluginState$lastI2 !== void 0 ? _newPluginState$lastI2 : null) || agentMentionParentNodeType !== ((_newPluginState$lastI3 = newPluginState.lastInsertedAgentMentionParentNodeType) !== null && _newPluginState$lastI3 !== void 0 ? _newPluginState$lastI3 : null) || newInsertionCount !== undefined) {
273
419
  newPluginState = {
274
420
  ...newPluginState,
275
421
  lastInsertedAgentMentionId: agentMentionId,
@@ -279,11 +425,19 @@ export function createMentionPlugin({
279
425
  lastAgentMentionInsertionCount: newInsertionCount
280
426
  } : {})
281
427
  };
282
- hasNewPluginState = true;
428
+ hasPublicPluginStateChanged = true;
283
429
  }
284
430
  }
285
431
  }
286
- if (hasNewPluginState && editorExperiment('platform_editor_agent_mentions', true)) {
432
+ if (isAgentMentionsExperimentEnabled && newPluginState.pendingTypedAgentMention && action !== ACTIONS.SET_PENDING_TYPED_AGENT_MENTION && action !== ACTIONS.COMMIT_PENDING_TYPED_AGENT_MENTION && tr.docChanged) {
433
+ newPluginState = {
434
+ ...newPluginState,
435
+ pendingTypedAgentMention: getPendingTypedAgentMentionAfterDocChange(newState, tr, newPluginState.pendingTypedAgentMention, {
436
+ resetTimer: isQualifyingLocalUserDocChange(tr)
437
+ })
438
+ };
439
+ }
440
+ if (hasPublicPluginStateChanged && isAgentMentionsExperimentEnabled) {
287
441
  pmPluginFactoryParams.dispatch(mentionPluginKey, newPluginState);
288
442
  }
289
443
  return newPluginState;
@@ -301,6 +455,47 @@ export function createMentionPlugin({
301
455
  }
302
456
  },
303
457
  view(editorView) {
458
+ const isAgentMentionsEnabled = editorExperiment('platform_editor_agent_mentions', true);
459
+ let pendingTypedAgentMentionTimer;
460
+ let pendingTypedAgentMentionTimerKey = null;
461
+ const clearPendingTypedAgentMentionTimer = () => {
462
+ if (pendingTypedAgentMentionTimer) {
463
+ clearTimeout(pendingTypedAgentMentionTimer);
464
+ pendingTypedAgentMentionTimer = undefined;
465
+ }
466
+ pendingTypedAgentMentionTimerKey = null;
467
+ };
468
+ const schedulePendingTypedAgentMentionTimer = mentionPluginState => {
469
+ if (!isAgentMentionsEnabled) {
470
+ clearPendingTypedAgentMentionTimer();
471
+ return;
472
+ }
473
+ const pendingTypedAgentMention = mentionPluginState === null || mentionPluginState === void 0 ? void 0 : mentionPluginState.pendingTypedAgentMention;
474
+ if (!pendingTypedAgentMention) {
475
+ clearPendingTypedAgentMentionTimer();
476
+ return;
477
+ }
478
+ const timerKey = `${pendingTypedAgentMention.localId}:${pendingTypedAgentMention.resetCount}`;
479
+ if (timerKey === pendingTypedAgentMentionTimerKey) {
480
+ return;
481
+ }
482
+ clearPendingTypedAgentMentionTimer();
483
+ pendingTypedAgentMentionTimerKey = timerKey;
484
+ pendingTypedAgentMentionTimer = setTimeout(() => {
485
+ var _mentionPluginKey$get;
486
+ const latestPendingTypedAgentMention = (_mentionPluginKey$get = mentionPluginKey.getState(editorView.state)) === null || _mentionPluginKey$get === void 0 ? void 0 : _mentionPluginKey$get.pendingTypedAgentMention;
487
+ if (!latestPendingTypedAgentMention || latestPendingTypedAgentMention.localId !== pendingTypedAgentMention.localId || latestPendingTypedAgentMention.resetCount !== pendingTypedAgentMention.resetCount) {
488
+ return;
489
+ }
490
+ editorView.dispatch(editorView.state.tr.setMeta(mentionPluginKey, {
491
+ action: ACTIONS.COMMIT_PENDING_TYPED_AGENT_MENTION,
492
+ params: {
493
+ localId: pendingTypedAgentMention.localId,
494
+ resetCount: pendingTypedAgentMention.resetCount
495
+ }
496
+ }));
497
+ }, AGENT_MENTION_INACTIVITY_MS);
498
+ };
304
499
  const providerHandler = (name, providerPromise) => {
305
500
  switch (name) {
306
501
  case 'mentionProvider':
@@ -346,7 +541,15 @@ export function createMentionPlugin({
346
541
  pmPluginFactoryParams.providerFactory.subscribe('mentionProvider', providerHandler);
347
542
  }
348
543
  return {
544
+ update(view, prevState) {
545
+ const mentionPluginState = mentionPluginKey.getState(view.state);
546
+ if (mentionPluginState === mentionPluginKey.getState(prevState)) {
547
+ return;
548
+ }
549
+ schedulePendingTypedAgentMentionTimer(mentionPluginState);
550
+ },
349
551
  destroy() {
552
+ clearPendingTypedAgentMentionTimer();
350
553
  if (pmPluginFactoryParams.providerFactory) {
351
554
  pmPluginFactoryParams.providerFactory.unsubscribe('mentionProvider', providerHandler);
352
555
  }
@@ -12,6 +12,8 @@ import { fg } from '@atlaskit/platform-feature-flags';
12
12
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
13
13
  import { expVal } from '@atlaskit/tmp-editor-statsig/expVal';
14
14
  import { createSingleMentionFragment } from '../../editor-commands';
15
+ import { mentionPluginKey } from '../../pm-plugins/key';
16
+ import { ACTIONS } from '../../pm-plugins/main';
15
17
  import { mentionPlaceholderPluginKey, MENTION_PLACEHOLDER_ACTIONS } from '../../pm-plugins/mentionPlaceholder';
16
18
  import { getMentionPluginState } from '../../pm-plugins/utils';
17
19
  import InviteItem, { INVITE_ITEM_DESCRIPTION } from '../InviteItem';
@@ -362,10 +364,10 @@ export const createTypeAheadConfig = ({
362
364
  sessionId
363
365
  };
364
366
  const isAgentMentionsExperimentEnabled = expVal('platform_editor_agent_mentions', 'isEnabled', false);
365
- const shouldSuppressInviteForAgentMention = isAgentMentionsExperimentEnabled && isAgentMention(item.mention);
367
+ const isAgentMentionInsertion = isAgentMentionsExperimentEnabled && isAgentMention(item.mention);
366
368
  // userType can be missing for provider-only agent mentions. Copy/paste cannot
367
369
  // see appType, so persist APP only when there is no explicit userType.
368
- const persistedUserType = isAgentMentionsExperimentEnabled && isAgentMention(item.mention) && userType == null ? 'APP' : userType;
370
+ const persistedUserType = isAgentMentionInsertion && userType == null ? 'APP' : userType;
369
371
  if (mentionProvider && !isInviteItem(item.mention)) {
370
372
  mentionProvider.recordMentionSelection(item.mention, mentionContext);
371
373
  }
@@ -424,7 +426,7 @@ export const createTypeAheadConfig = ({
424
426
  localId: mentionLocalId,
425
427
  method: 'typed',
426
428
  type: 'added',
427
- ...(shouldSuppressInviteForAgentMention ? {
429
+ ...(isAgentMentionInsertion ? {
428
430
  shouldSuppressMentionNotification: true
429
431
  } : {})
430
432
  };
@@ -437,22 +439,22 @@ export const createTypeAheadConfig = ({
437
439
  handleMentionsChanged([mentionChange]);
438
440
  }
439
441
  }
440
- fireEvent(buildTypeAheadInsertedPayload(pickerElapsedTime, stats.keyCount.arrowUp, stats.keyCount.arrowDown, sessionId, mode, item.mention, mentionLocalId, sourceListItem.map(x => x.mention), query, contextIdentifierProvider, taskListId, taskItemId, shouldSuppressInviteForAgentMention));
442
+ fireEvent(buildTypeAheadInsertedPayload(pickerElapsedTime, stats.keyCount.arrowUp, stats.keyCount.arrowDown, sessionId, mode, item.mention, mentionLocalId, sourceListItem.map(x => x.mention), query, contextIdentifierProvider, taskListId, taskItemId, isAgentMentionInsertion));
441
443
 
442
444
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
443
445
  sessionId = uuid();
444
446
  if (mentionProvider && isTeamType(userType)) {
445
447
  return insert(buildNodesForTeamMention(schema, item.mention, mentionProvider, sanitizePrivateContent));
446
448
  }
447
- if (!shouldSuppressInviteForAgentMention && isXProductUser && mentionProvider && mentionProvider.inviteXProductUser) {
449
+ if (!isAgentMentionInsertion && isXProductUser && mentionProvider && mentionProvider.inviteXProductUser) {
448
450
  mentionProvider.inviteXProductUser(id, name);
449
451
  }
450
- return insert(createSingleMentionFragment({
452
+ const tr = insert(createSingleMentionFragment({
451
453
  mentionProvider,
452
454
  mentionInsertDisplayName,
453
455
  tr: state.tr,
454
456
  sanitizePrivateContent,
455
- suppressInviteXProductUser: shouldSuppressInviteForAgentMention
457
+ suppressInviteXProductUser: isAgentMentionInsertion
456
458
  })({
457
459
  name,
458
460
  id,
@@ -462,6 +464,15 @@ export const createTypeAheadConfig = ({
462
464
  accessLevel,
463
465
  isXProductUser
464
466
  }));
467
+ if (isAgentMentionInsertion) {
468
+ tr.setMeta(mentionPluginKey, {
469
+ action: ACTIONS.SET_PENDING_TYPED_AGENT_MENTION,
470
+ params: {
471
+ localId: mentionLocalId
472
+ }
473
+ });
474
+ }
475
+ return tr;
465
476
  },
466
477
  dismiss({
467
478
  editorState,