@atlaskit/collab-provider 24.0.0 → 24.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @atlaskit/collab-provider
2
2
 
3
+ ## 24.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`d7528657a607f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/d7528657a607f) -
8
+ Feature-gate and serialize agent attribution from matching transaction origins onto native-collab
9
+ steps.
10
+ - Updated dependencies
11
+
12
+ ## 24.0.1
13
+
14
+ ### Patch Changes
15
+
16
+ - [`e3cd2bd6f960a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e3cd2bd6f960a) -
17
+ Fix agent presence lifecycle behind platform_move_presence_agents.
18
+ - Updated dependencies
19
+
3
20
  ## 24.0.0
4
21
 
5
22
  ### Patch Changes
@@ -4,12 +4,14 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.SINGLE_COLLAB_MODE = exports.ParticipantsService = exports.MULTI_COLLAB_MODE = exports.AGENT_PRESENCE_TTL_MS = void 0;
7
+ exports.SINGLE_COLLAB_MODE = exports.ParticipantsService = exports.MULTI_COLLAB_MODE = exports.AGENT_PRESENCE_TTL_MS = exports.AGENT_PRESENCE_INACTIVE_MS = void 0;
8
8
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
10
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
11
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
12
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
12
13
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
14
+ var _fg = require("@atlaskit/platform-feature-flags/fg");
13
15
  var _disconnectedReasonMapper = require("../disconnected-reason-mapper");
14
16
  var _const = require("../helpers/const");
15
17
  var _telepointersHelper = require("./telepointers-helper");
@@ -28,7 +30,8 @@ var MULTI_COLLAB_MODE = exports.MULTI_COLLAB_MODE = 'collab';
28
30
  // Sliding inactivity window for agent (AI provider) participants that are added locally from
29
31
  // remote agent-authored steps. Reset on each new step for that agent.
30
32
  // NOTE: temporary/demonstration lifecycle — long-term expiry may move to NCS.
31
- var AGENT_PRESENCE_TTL_MS = exports.AGENT_PRESENCE_TTL_MS = 30 * 1000; // 30 seconds
33
+ var AGENT_PRESENCE_INACTIVE_MS = exports.AGENT_PRESENCE_INACTIVE_MS = 30 * 1000; // 30 seconds
34
+ var AGENT_PRESENCE_TTL_MS = exports.AGENT_PRESENCE_TTL_MS = 5 * 60 * 1000; // 5 minutes
32
35
 
33
36
  /**
34
37
  * This service is responsible for handling presence and participant events, as well as sending them on to the editor or NCS.
@@ -138,6 +141,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
138
141
  var payload = _this.buildAIProviderPresencePayload(providerId);
139
142
  var sessionId = payload.sessionId;
140
143
  var existing = _this.participantsState.getBySessionId(sessionId);
144
+ var wasInactive = existing ? Date.now() - existing.lastActive >= AGENT_PRESENCE_INACTIVE_MS : false;
141
145
  var participant = _objectSpread(_objectSpread({}, payload), {}, {
142
146
  // `payload.userId` is typed `string | undefined`; here it is always the (string)
143
147
  // providerId, so pin it to satisfy ProviderParticipant.userId (string).
@@ -152,26 +156,46 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
152
156
  });
153
157
  _this.participantsState.setBySessionId(sessionId, participant);
154
158
 
155
- // Emit only on the first add; a refresh of an already-present agent shouldn't re-emit.
156
- if (!existing) {
159
+ // Active refreshes stay silent. Re-emit when an inactive agent becomes active so consumers
160
+ // can update its presentation immediately.
161
+ if (!existing || (0, _fg.fg)('platform_move_presence_agents') && wasInactive) {
157
162
  _this.emitPresence({
158
163
  joined: [participant]
159
164
  }, 'adding agent participant from remote step');
160
165
  }
161
- _this.resetAgentPresenceTimer(sessionId);
166
+ _this.resetAgentPresenceTimer(sessionId, participant.lastActive);
162
167
  });
163
168
  /**
164
- * (Re)starts the sliding 30s inactivity timer for an agent participant. Called on every agent
165
- * step so the window slides forward from the agent's most recent activity.
169
+ * (Re)starts the sliding expiry timer for an agent participant. The enriched lifecycle retains
170
+ * agents for five minutes, while the legacy lifecycle keeps its 30-second removal behavior.
166
171
  */
167
- (0, _defineProperty2.default)(this, "resetAgentPresenceTimer", function (sessionId) {
172
+ (0, _defineProperty2.default)(this, "resetAgentPresenceTimer", function (sessionId, lastActive) {
168
173
  var existingTimer = _this.agentPresenceTimers.get(sessionId);
169
174
  if (existingTimer !== undefined) {
170
175
  clearTimeout(existingTimer);
171
176
  }
177
+ var ttl = (0, _fg.fg)('platform_move_presence_agents') ? AGENT_PRESENCE_TTL_MS : AGENT_PRESENCE_INACTIVE_MS;
178
+ var delay = Math.max(0, lastActive + ttl - Date.now());
172
179
  _this.agentPresenceTimers.set(sessionId, window.setTimeout(function () {
173
180
  return _this.removeAgentParticipant(sessionId);
174
- }, AGENT_PRESENCE_TTL_MS));
181
+ }, delay));
182
+ });
183
+ (0, _defineProperty2.default)(this, "scheduleRemoteAgentExpiry", function (participant) {
184
+ if (!(0, _fg.fg)('platform_move_presence_agents') || !(0, _utils.isAIProviderID)(participant.userId) || !Number.isFinite(participant.lastActive)) {
185
+ return;
186
+ }
187
+ _this.resetAgentPresenceTimer(participant.sessionId, participant.lastActive);
188
+ });
189
+ (0, _defineProperty2.default)(this, "clearAgentPresenceTimer", function (sessionId) {
190
+ var timer = _this.agentPresenceTimers.get(sessionId);
191
+ if (timer !== undefined) {
192
+ clearTimeout(timer);
193
+ _this.agentPresenceTimers.delete(sessionId);
194
+ }
195
+ });
196
+ (0, _defineProperty2.default)(this, "hasAgentBecomeActive", function (previous, current) {
197
+ var now = Date.now();
198
+ return (0, _fg.fg)('platform_move_presence_agents') && (0, _utils.isAIProviderID)(current.userId) && now - previous.lastActive >= AGENT_PRESENCE_INACTIVE_MS && now - current.lastActive < AGENT_PRESENCE_INACTIVE_MS;
175
199
  });
176
200
  /**
177
201
  * Removes an inactive agent participant once its sliding window elapses and emits the `presence`
@@ -299,11 +323,12 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
299
323
  case 6:
300
324
  previousParticipant = _this.participantsState.getBySessionId(participant.sessionId);
301
325
  _this.participantsState.setBySessionId(participant.sessionId, participant);
326
+ _this.scheduleRemoteAgentExpiry(participant);
302
327
  if (!previousParticipant) {
303
328
  _context2.next = 7;
304
329
  break;
305
330
  }
306
- if (_this.hasActingUserChanged(previousParticipant, participant)) {
331
+ if (_this.hasActingUserChanged(previousParticipant, participant) || _this.hasAgentBecomeActive(previousParticipant, participant)) {
307
332
  _this.emitPresence({
308
333
  joined: [participant]
309
334
  }, 'handling participant acting user changed event');
@@ -376,6 +401,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
376
401
  _context3.next = 3;
377
402
  break;
378
403
  }
404
+ _this.scheduleRemoteAgentExpiry(_participant);
379
405
  _this.emitPresence({
380
406
  joined: [_participant]
381
407
  }, 'handling updated new agent lazy');
@@ -404,7 +430,8 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
404
430
  lastActive: payload.timestamp
405
431
  });
406
432
  _this.participantsState.setBySessionId(sessionId, participant);
407
- if (_this.hasActingUserChanged(previousParticipant, participant)) {
433
+ _this.scheduleRemoteAgentExpiry(participant);
434
+ if (_this.hasActingUserChanged(previousParticipant, participant) || _this.hasAgentBecomeActive(previousParticipant, participant)) {
408
435
  _this.emitPresence({
409
436
  joined: [participant]
410
437
  }, 'handling participant acting user changed event');
@@ -480,6 +507,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
480
507
  });
481
508
  });
482
509
  }
510
+ _this.clearAgentPresenceTimer(sessionId);
483
511
  _this.participantsState.removeBySessionId(sessionId);
484
512
  _this.emitPresence({
485
513
  left: [{
@@ -488,7 +516,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
488
516
  }, 'participant leaving');
489
517
  });
490
518
  (0, _defineProperty2.default)(this, "disconnect", function (reason, sessionId) {
491
- var left = _this.participantsState.getParticipants();
519
+ var left = (0, _fg.fg)('platform_move_presence_agents') ? [].concat((0, _toConsumableArray2.default)(_this.participantsState.getParticipants()), (0, _toConsumableArray2.default)(_this.participantsState.getAIProviderParticipants())) : _this.participantsState.getParticipants();
492
520
  _this.participantsState.clear();
493
521
  // Stop any pending agent presence timers so they don't fire against cleared state.
494
522
  _this.clearAgentPresenceTimers();
@@ -13,6 +13,8 @@ var _const = require("../helpers/const");
13
13
  var _types = require("../types");
14
14
  var _ncsErrors = require("../errors/ncs-errors");
15
15
  var _utils = require("../helpers/utils");
16
+ var _transactionAgentAttribution = require("@atlaskit/editor-common/transaction-agent-attribution");
17
+ var _fg = require("@atlaskit/platform-feature-flags/fg");
16
18
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
17
19
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
18
20
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -36,6 +38,7 @@ var CommitStepService = exports.CommitStepService = /*#__PURE__*/function () {
36
38
  this.onErrorHandled = onErrorHandled;
37
39
  this.readyToCommit = true;
38
40
  this.lastBroadcastRequestAcked = true;
41
+ this.shouldSerializeAgentAttribution = (0, _fg.fg)('platform_editor_agentic_step_attribution');
39
42
  }
40
43
  return (0, _createClass2.default)(CommitStepService, [{
41
44
  key: "commitStepQueue",
@@ -75,11 +78,17 @@ var CommitStepService = exports.CommitStepService = /*#__PURE__*/function () {
75
78
  _this.lastBroadcastRequestAcked = true;
76
79
  logger('reset readyToCommit by timer');
77
80
  }, RESET_READYTOCOMMIT_INTERVAL_MS);
78
- var stepsWithClientAndUserId = steps.map(function (step) {
81
+ var stepsWithClientAndUserId = steps.map(function (step, index) {
82
+ var _stepOrigins$index;
83
+ var agentAttribution = _this.shouldSerializeAgentAttribution ? stepOrigins === null || stepOrigins === void 0 || (_stepOrigins$index = stepOrigins[index]) === null || _stepOrigins$index === void 0 ? void 0 : _stepOrigins$index.getMeta(_transactionAgentAttribution.AGENT_ATTRIBUTION_META) : undefined;
79
84
  return _objectSpread(_objectSpread({}, step.toJSON()), {}, {
80
85
  clientId: clientId,
81
86
  userId: userId
82
- });
87
+ }, agentAttribution ? _objectSpread({
88
+ agentType: agentAttribution.agentType
89
+ }, agentAttribution.agentId !== undefined ? {
90
+ agentId: agentAttribution.agentId
91
+ } : {}) : {});
83
92
  });
84
93
 
85
94
  // Mutate steps to ignore expand expand/collapse changes in live pages
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.version = exports.nextMajorVersion = exports.name = void 0;
7
7
  var name = exports.name = "@atlaskit/collab-provider";
8
- var version = exports.version = "23.1.0";
8
+ var version = exports.version = "24.0.2";
9
9
  var nextMajorVersion = exports.nextMajorVersion = function nextMajorVersion() {
10
10
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
11
11
  };
@@ -1,4 +1,5 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
2
3
  import { disconnectedReasonMapper } from '../disconnected-reason-mapper';
3
4
  import { EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
4
5
  import { telepointerFromStep } from './telepointers-helper';
@@ -15,7 +16,8 @@ export const MULTI_COLLAB_MODE = 'collab';
15
16
  // Sliding inactivity window for agent (AI provider) participants that are added locally from
16
17
  // remote agent-authored steps. Reset on each new step for that agent.
17
18
  // NOTE: temporary/demonstration lifecycle — long-term expiry may move to NCS.
18
- export const AGENT_PRESENCE_TTL_MS = 30 * 1000; // 30 seconds
19
+ export const AGENT_PRESENCE_INACTIVE_MS = 30 * 1000; // 30 seconds
20
+ export const AGENT_PRESENCE_TTL_MS = 5 * 60 * 1000; // 5 minutes
19
21
 
20
22
  /**
21
23
  * This service is responsible for handling presence and participant events, as well as sending them on to the editor or NCS.
@@ -125,6 +127,7 @@ export class ParticipantsService {
125
127
  sessionId
126
128
  } = payload;
127
129
  const existing = this.participantsState.getBySessionId(sessionId);
130
+ const wasInactive = existing ? Date.now() - existing.lastActive >= AGENT_PRESENCE_INACTIVE_MS : false;
128
131
  const participant = {
129
132
  ...payload,
130
133
  // `payload.userId` is typed `string | undefined`; here it is always the (string)
@@ -140,24 +143,44 @@ export class ParticipantsService {
140
143
  };
141
144
  this.participantsState.setBySessionId(sessionId, participant);
142
145
 
143
- // Emit only on the first add; a refresh of an already-present agent shouldn't re-emit.
144
- if (!existing) {
146
+ // Active refreshes stay silent. Re-emit when an inactive agent becomes active so consumers
147
+ // can update its presentation immediately.
148
+ if (!existing || fg('platform_move_presence_agents') && wasInactive) {
145
149
  this.emitPresence({
146
150
  joined: [participant]
147
151
  }, 'adding agent participant from remote step');
148
152
  }
149
- this.resetAgentPresenceTimer(sessionId);
153
+ this.resetAgentPresenceTimer(sessionId, participant.lastActive);
150
154
  });
151
155
  /**
152
- * (Re)starts the sliding 30s inactivity timer for an agent participant. Called on every agent
153
- * step so the window slides forward from the agent's most recent activity.
156
+ * (Re)starts the sliding expiry timer for an agent participant. The enriched lifecycle retains
157
+ * agents for five minutes, while the legacy lifecycle keeps its 30-second removal behavior.
154
158
  */
155
- _defineProperty(this, "resetAgentPresenceTimer", sessionId => {
159
+ _defineProperty(this, "resetAgentPresenceTimer", (sessionId, lastActive) => {
156
160
  const existingTimer = this.agentPresenceTimers.get(sessionId);
157
161
  if (existingTimer !== undefined) {
158
162
  clearTimeout(existingTimer);
159
163
  }
160
- this.agentPresenceTimers.set(sessionId, window.setTimeout(() => this.removeAgentParticipant(sessionId), AGENT_PRESENCE_TTL_MS));
164
+ const ttl = fg('platform_move_presence_agents') ? AGENT_PRESENCE_TTL_MS : AGENT_PRESENCE_INACTIVE_MS;
165
+ const delay = Math.max(0, lastActive + ttl - Date.now());
166
+ this.agentPresenceTimers.set(sessionId, window.setTimeout(() => this.removeAgentParticipant(sessionId), delay));
167
+ });
168
+ _defineProperty(this, "scheduleRemoteAgentExpiry", participant => {
169
+ if (!fg('platform_move_presence_agents') || !isAIProviderID(participant.userId) || !Number.isFinite(participant.lastActive)) {
170
+ return;
171
+ }
172
+ this.resetAgentPresenceTimer(participant.sessionId, participant.lastActive);
173
+ });
174
+ _defineProperty(this, "clearAgentPresenceTimer", sessionId => {
175
+ const timer = this.agentPresenceTimers.get(sessionId);
176
+ if (timer !== undefined) {
177
+ clearTimeout(timer);
178
+ this.agentPresenceTimers.delete(sessionId);
179
+ }
180
+ });
181
+ _defineProperty(this, "hasAgentBecomeActive", (previous, current) => {
182
+ const now = Date.now();
183
+ return fg('platform_move_presence_agents') && isAIProviderID(current.userId) && now - previous.lastActive >= AGENT_PRESENCE_INACTIVE_MS && now - current.lastActive < AGENT_PRESENCE_INACTIVE_MS;
161
184
  });
162
185
  /**
163
186
  * Removes an inactive agent participant once its sliding window elapses and emits the `presence`
@@ -252,8 +275,9 @@ export class ParticipantsService {
252
275
  }
253
276
  const previousParticipant = this.participantsState.getBySessionId(participant.sessionId);
254
277
  this.participantsState.setBySessionId(participant.sessionId, participant);
278
+ this.scheduleRemoteAgentExpiry(participant);
255
279
  if (previousParticipant) {
256
- if (this.hasActingUserChanged(previousParticipant, participant)) {
280
+ if (this.hasActingUserChanged(previousParticipant, participant) || this.hasAgentBecomeActive(previousParticipant, participant)) {
257
281
  this.emitPresence({
258
282
  joined: [participant]
259
283
  }, 'handling participant acting user changed event');
@@ -309,6 +333,7 @@ export class ParticipantsService {
309
333
  };
310
334
  this.participantsState.setBySessionId(sessionId, participant);
311
335
  if (isAIProviderID(userId)) {
336
+ this.scheduleRemoteAgentExpiry(participant);
312
337
  this.emitPresence({
313
338
  joined: [participant]
314
339
  }, 'handling updated new agent lazy');
@@ -340,7 +365,8 @@ export class ParticipantsService {
340
365
  lastActive: payload.timestamp
341
366
  };
342
367
  this.participantsState.setBySessionId(sessionId, participant);
343
- if (this.hasActingUserChanged(previousParticipant, participant)) {
368
+ this.scheduleRemoteAgentExpiry(participant);
369
+ if (this.hasActingUserChanged(previousParticipant, participant) || this.hasAgentBecomeActive(previousParticipant, participant)) {
344
370
  this.emitPresence({
345
371
  joined: [participant]
346
372
  }, 'handling participant acting user changed event');
@@ -387,6 +413,7 @@ export class ParticipantsService {
387
413
  });
388
414
  });
389
415
  }
416
+ this.clearAgentPresenceTimer(sessionId);
390
417
  this.participantsState.removeBySessionId(sessionId);
391
418
  this.emitPresence({
392
419
  left: [{
@@ -395,7 +422,7 @@ export class ParticipantsService {
395
422
  }, 'participant leaving');
396
423
  });
397
424
  _defineProperty(this, "disconnect", (reason, sessionId) => {
398
- const left = this.participantsState.getParticipants();
425
+ const left = fg('platform_move_presence_agents') ? [...this.participantsState.getParticipants(), ...this.participantsState.getAIProviderParticipants()] : this.participantsState.getParticipants();
399
426
  this.participantsState.clear();
400
427
  // Stop any pending agent presence timers so they don't fire against cleared state.
401
428
  this.clearAgentPresenceTimers();
@@ -3,6 +3,8 @@ import { ADD_STEPS_TYPE, EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
3
3
  import { AcknowledgementResponseTypes } from '../types';
4
4
  import { NCS_ERROR_CODE } from '../errors/ncs-errors';
5
5
  import { createLogger } from '../helpers/utils';
6
+ import { AGENT_ATTRIBUTION_META } from '@atlaskit/editor-common/transaction-agent-attribution';
7
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
6
8
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
7
9
  const logger = createLogger('commit-step', 'black');
8
10
  export const RESET_READYTOCOMMIT_INTERVAL_MS = 5000;
@@ -23,6 +25,7 @@ export class CommitStepService {
23
25
  this.onErrorHandled = onErrorHandled;
24
26
  this.readyToCommit = true;
25
27
  this.lastBroadcastRequestAcked = true;
28
+ this.shouldSerializeAgentAttribution = fg('platform_editor_agentic_step_attribution');
26
29
  }
27
30
  commitStepQueue({
28
31
  steps,
@@ -60,11 +63,21 @@ export class CommitStepService {
60
63
  this.lastBroadcastRequestAcked = true;
61
64
  logger('reset readyToCommit by timer');
62
65
  }, RESET_READYTOCOMMIT_INTERVAL_MS);
63
- let stepsWithClientAndUserId = steps.map(step => ({
64
- ...step.toJSON(),
65
- clientId,
66
- userId
67
- }));
66
+ let stepsWithClientAndUserId = steps.map((step, index) => {
67
+ var _stepOrigins$index;
68
+ const agentAttribution = this.shouldSerializeAgentAttribution ? stepOrigins === null || stepOrigins === void 0 ? void 0 : (_stepOrigins$index = stepOrigins[index]) === null || _stepOrigins$index === void 0 ? void 0 : _stepOrigins$index.getMeta(AGENT_ATTRIBUTION_META) : undefined;
69
+ return {
70
+ ...step.toJSON(),
71
+ clientId,
72
+ userId,
73
+ ...(agentAttribution ? {
74
+ agentType: agentAttribution.agentType,
75
+ ...(agentAttribution.agentId !== undefined ? {
76
+ agentId: agentAttribution.agentId
77
+ } : {})
78
+ } : {})
79
+ };
80
+ });
68
81
 
69
82
  // Mutate steps to ignore expand expand/collapse changes in live pages
70
83
  // This is expected to be a temporary divergence from standard editor behaviour
@@ -1,5 +1,5 @@
1
1
  export const name = "@atlaskit/collab-provider";
2
- export const version = "23.1.0";
2
+ export const version = "24.0.2";
3
3
  export const nextMajorVersion = () => {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -1,3 +1,4 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
2
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
3
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
4
  import _createClass from "@babel/runtime/helpers/createClass";
@@ -5,6 +6,7 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
5
6
  import _regeneratorRuntime from "@babel/runtime/regenerator";
6
7
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
7
8
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
9
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
8
10
  import { disconnectedReasonMapper } from '../disconnected-reason-mapper';
9
11
  import { EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
10
12
  import { telepointerFromStep } from './telepointers-helper';
@@ -21,7 +23,8 @@ export var MULTI_COLLAB_MODE = 'collab';
21
23
  // Sliding inactivity window for agent (AI provider) participants that are added locally from
22
24
  // remote agent-authored steps. Reset on each new step for that agent.
23
25
  // NOTE: temporary/demonstration lifecycle — long-term expiry may move to NCS.
24
- export var AGENT_PRESENCE_TTL_MS = 30 * 1000; // 30 seconds
26
+ export var AGENT_PRESENCE_INACTIVE_MS = 30 * 1000; // 30 seconds
27
+ export var AGENT_PRESENCE_TTL_MS = 5 * 60 * 1000; // 5 minutes
25
28
 
26
29
  /**
27
30
  * This service is responsible for handling presence and participant events, as well as sending them on to the editor or NCS.
@@ -131,6 +134,7 @@ export var ParticipantsService = /*#__PURE__*/function () {
131
134
  var payload = _this.buildAIProviderPresencePayload(providerId);
132
135
  var sessionId = payload.sessionId;
133
136
  var existing = _this.participantsState.getBySessionId(sessionId);
137
+ var wasInactive = existing ? Date.now() - existing.lastActive >= AGENT_PRESENCE_INACTIVE_MS : false;
134
138
  var participant = _objectSpread(_objectSpread({}, payload), {}, {
135
139
  // `payload.userId` is typed `string | undefined`; here it is always the (string)
136
140
  // providerId, so pin it to satisfy ProviderParticipant.userId (string).
@@ -145,26 +149,46 @@ export var ParticipantsService = /*#__PURE__*/function () {
145
149
  });
146
150
  _this.participantsState.setBySessionId(sessionId, participant);
147
151
 
148
- // Emit only on the first add; a refresh of an already-present agent shouldn't re-emit.
149
- if (!existing) {
152
+ // Active refreshes stay silent. Re-emit when an inactive agent becomes active so consumers
153
+ // can update its presentation immediately.
154
+ if (!existing || fg('platform_move_presence_agents') && wasInactive) {
150
155
  _this.emitPresence({
151
156
  joined: [participant]
152
157
  }, 'adding agent participant from remote step');
153
158
  }
154
- _this.resetAgentPresenceTimer(sessionId);
159
+ _this.resetAgentPresenceTimer(sessionId, participant.lastActive);
155
160
  });
156
161
  /**
157
- * (Re)starts the sliding 30s inactivity timer for an agent participant. Called on every agent
158
- * step so the window slides forward from the agent's most recent activity.
162
+ * (Re)starts the sliding expiry timer for an agent participant. The enriched lifecycle retains
163
+ * agents for five minutes, while the legacy lifecycle keeps its 30-second removal behavior.
159
164
  */
160
- _defineProperty(this, "resetAgentPresenceTimer", function (sessionId) {
165
+ _defineProperty(this, "resetAgentPresenceTimer", function (sessionId, lastActive) {
161
166
  var existingTimer = _this.agentPresenceTimers.get(sessionId);
162
167
  if (existingTimer !== undefined) {
163
168
  clearTimeout(existingTimer);
164
169
  }
170
+ var ttl = fg('platform_move_presence_agents') ? AGENT_PRESENCE_TTL_MS : AGENT_PRESENCE_INACTIVE_MS;
171
+ var delay = Math.max(0, lastActive + ttl - Date.now());
165
172
  _this.agentPresenceTimers.set(sessionId, window.setTimeout(function () {
166
173
  return _this.removeAgentParticipant(sessionId);
167
- }, AGENT_PRESENCE_TTL_MS));
174
+ }, delay));
175
+ });
176
+ _defineProperty(this, "scheduleRemoteAgentExpiry", function (participant) {
177
+ if (!fg('platform_move_presence_agents') || !isAIProviderID(participant.userId) || !Number.isFinite(participant.lastActive)) {
178
+ return;
179
+ }
180
+ _this.resetAgentPresenceTimer(participant.sessionId, participant.lastActive);
181
+ });
182
+ _defineProperty(this, "clearAgentPresenceTimer", function (sessionId) {
183
+ var timer = _this.agentPresenceTimers.get(sessionId);
184
+ if (timer !== undefined) {
185
+ clearTimeout(timer);
186
+ _this.agentPresenceTimers.delete(sessionId);
187
+ }
188
+ });
189
+ _defineProperty(this, "hasAgentBecomeActive", function (previous, current) {
190
+ var now = Date.now();
191
+ return fg('platform_move_presence_agents') && isAIProviderID(current.userId) && now - previous.lastActive >= AGENT_PRESENCE_INACTIVE_MS && now - current.lastActive < AGENT_PRESENCE_INACTIVE_MS;
168
192
  });
169
193
  /**
170
194
  * Removes an inactive agent participant once its sliding window elapses and emits the `presence`
@@ -292,11 +316,12 @@ export var ParticipantsService = /*#__PURE__*/function () {
292
316
  case 6:
293
317
  previousParticipant = _this.participantsState.getBySessionId(participant.sessionId);
294
318
  _this.participantsState.setBySessionId(participant.sessionId, participant);
319
+ _this.scheduleRemoteAgentExpiry(participant);
295
320
  if (!previousParticipant) {
296
321
  _context2.next = 7;
297
322
  break;
298
323
  }
299
- if (_this.hasActingUserChanged(previousParticipant, participant)) {
324
+ if (_this.hasActingUserChanged(previousParticipant, participant) || _this.hasAgentBecomeActive(previousParticipant, participant)) {
300
325
  _this.emitPresence({
301
326
  joined: [participant]
302
327
  }, 'handling participant acting user changed event');
@@ -369,6 +394,7 @@ export var ParticipantsService = /*#__PURE__*/function () {
369
394
  _context3.next = 3;
370
395
  break;
371
396
  }
397
+ _this.scheduleRemoteAgentExpiry(_participant);
372
398
  _this.emitPresence({
373
399
  joined: [_participant]
374
400
  }, 'handling updated new agent lazy');
@@ -397,7 +423,8 @@ export var ParticipantsService = /*#__PURE__*/function () {
397
423
  lastActive: payload.timestamp
398
424
  });
399
425
  _this.participantsState.setBySessionId(sessionId, participant);
400
- if (_this.hasActingUserChanged(previousParticipant, participant)) {
426
+ _this.scheduleRemoteAgentExpiry(participant);
427
+ if (_this.hasActingUserChanged(previousParticipant, participant) || _this.hasAgentBecomeActive(previousParticipant, participant)) {
401
428
  _this.emitPresence({
402
429
  joined: [participant]
403
430
  }, 'handling participant acting user changed event');
@@ -473,6 +500,7 @@ export var ParticipantsService = /*#__PURE__*/function () {
473
500
  });
474
501
  });
475
502
  }
503
+ _this.clearAgentPresenceTimer(sessionId);
476
504
  _this.participantsState.removeBySessionId(sessionId);
477
505
  _this.emitPresence({
478
506
  left: [{
@@ -481,7 +509,7 @@ export var ParticipantsService = /*#__PURE__*/function () {
481
509
  }, 'participant leaving');
482
510
  });
483
511
  _defineProperty(this, "disconnect", function (reason, sessionId) {
484
- var left = _this.participantsState.getParticipants();
512
+ var left = fg('platform_move_presence_agents') ? [].concat(_toConsumableArray(_this.participantsState.getParticipants()), _toConsumableArray(_this.participantsState.getAIProviderParticipants())) : _this.participantsState.getParticipants();
485
513
  _this.participantsState.clear();
486
514
  // Stop any pending agent presence timers so they don't fire against cleared state.
487
515
  _this.clearAgentPresenceTimers();
@@ -8,6 +8,8 @@ import { ADD_STEPS_TYPE, EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
8
8
  import { AcknowledgementResponseTypes } from '../types';
9
9
  import { NCS_ERROR_CODE } from '../errors/ncs-errors';
10
10
  import { createLogger } from '../helpers/utils';
11
+ import { AGENT_ATTRIBUTION_META } from '@atlaskit/editor-common/transaction-agent-attribution';
12
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
11
13
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
12
14
  var logger = createLogger('commit-step', 'black');
13
15
  export var RESET_READYTOCOMMIT_INTERVAL_MS = 5000;
@@ -29,6 +31,7 @@ export var CommitStepService = /*#__PURE__*/function () {
29
31
  this.onErrorHandled = onErrorHandled;
30
32
  this.readyToCommit = true;
31
33
  this.lastBroadcastRequestAcked = true;
34
+ this.shouldSerializeAgentAttribution = fg('platform_editor_agentic_step_attribution');
32
35
  }
33
36
  return _createClass(CommitStepService, [{
34
37
  key: "commitStepQueue",
@@ -68,11 +71,17 @@ export var CommitStepService = /*#__PURE__*/function () {
68
71
  _this.lastBroadcastRequestAcked = true;
69
72
  logger('reset readyToCommit by timer');
70
73
  }, RESET_READYTOCOMMIT_INTERVAL_MS);
71
- var stepsWithClientAndUserId = steps.map(function (step) {
74
+ var stepsWithClientAndUserId = steps.map(function (step, index) {
75
+ var _stepOrigins$index;
76
+ var agentAttribution = _this.shouldSerializeAgentAttribution ? stepOrigins === null || stepOrigins === void 0 || (_stepOrigins$index = stepOrigins[index]) === null || _stepOrigins$index === void 0 ? void 0 : _stepOrigins$index.getMeta(AGENT_ATTRIBUTION_META) : undefined;
72
77
  return _objectSpread(_objectSpread({}, step.toJSON()), {}, {
73
78
  clientId: clientId,
74
79
  userId: userId
75
- });
80
+ }, agentAttribution ? _objectSpread({
81
+ agentType: agentAttribution.agentType
82
+ }, agentAttribution.agentId !== undefined ? {
83
+ agentId: agentAttribution.agentId
84
+ } : {}) : {});
76
85
  });
77
86
 
78
87
  // Mutate steps to ignore expand expand/collapse changes in live pages
@@ -1,5 +1,5 @@
1
1
  export var name = "@atlaskit/collab-provider";
2
- export var version = "23.1.0";
2
+ export var version = "24.0.2";
3
3
  export var nextMajorVersion = function nextMajorVersion() {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -6,6 +6,7 @@ import { ParticipantsState } from './participants-state';
6
6
  import type { ParticipantFilter } from './participants-state';
7
7
  export declare const SINGLE_COLLAB_MODE = "single";
8
8
  export declare const MULTI_COLLAB_MODE = "collab";
9
+ export declare const AGENT_PRESENCE_INACTIVE_MS: number;
9
10
  export declare const AGENT_PRESENCE_TTL_MS: number;
10
11
  /**
11
12
  * This service is responsible for handling presence and participant events, as well as sending them on to the editor or NCS.
@@ -85,10 +86,13 @@ export declare class ParticipantsService {
85
86
  */
86
87
  upsertAIProviderParticipantLocally: (providerId: string) => void;
87
88
  /**
88
- * (Re)starts the sliding 30s inactivity timer for an agent participant. Called on every agent
89
- * step so the window slides forward from the agent's most recent activity.
89
+ * (Re)starts the sliding expiry timer for an agent participant. The enriched lifecycle retains
90
+ * agents for five minutes, while the legacy lifecycle keeps its 30-second removal behavior.
90
91
  */
91
92
  private resetAgentPresenceTimer;
93
+ private scheduleRemoteAgentExpiry;
94
+ private clearAgentPresenceTimer;
95
+ private hasAgentBecomeActive;
92
96
  /**
93
97
  * Removes an inactive agent participant once its sliding window elapses and emits the `presence`
94
98
  * leave so the facepile drops it.
@@ -13,6 +13,7 @@ export declare class CommitStepService {
13
13
  private onErrorHandled;
14
14
  private readyToCommit;
15
15
  private lastBroadcastRequestAcked;
16
+ private readonly shouldSerializeAgentAttribution;
16
17
  /**
17
18
  * @param broadcast - Callback for broadcasting events to other clients
18
19
  * @param analyticsHelper - Helper for analytics events
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/collab-provider",
3
- "version": "24.0.0",
3
+ "version": "24.0.2",
4
4
  "description": "A provider for collaborative editing.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -18,18 +18,18 @@
18
18
  "team": "Editor: Collaboration"
19
19
  },
20
20
  "dependencies": {
21
- "@atlaskit/adf-utils": "^20.5.0",
21
+ "@atlaskit/adf-utils": "^20.6.0",
22
22
  "@atlaskit/analytics-gas-types": "^6.0.0",
23
23
  "@atlaskit/analytics-listeners": "^11.1.0",
24
24
  "@atlaskit/anonymous-assets": "^2.8.0",
25
25
  "@atlaskit/atlassian-context": "^1.1.0",
26
- "@atlaskit/editor-json-transformer": "^9.2.0",
26
+ "@atlaskit/editor-json-transformer": "^9.4.0",
27
27
  "@atlaskit/editor-prosemirror": "^8.0.0",
28
28
  "@atlaskit/feature-gate-js-client": "^6.0.0",
29
29
  "@atlaskit/platform-feature-experiments": "^0.3.0",
30
30
  "@atlaskit/platform-feature-flags": "^2.1.0",
31
31
  "@atlaskit/prosemirror-collab": "^1.0.0",
32
- "@atlaskit/react-ufo": "^7.5.0",
32
+ "@atlaskit/react-ufo": "^7.6.0",
33
33
  "@atlaskit/tmp-editor-statsig": "^147.1.0",
34
34
  "@atlaskit/ufo": "^1.0.0",
35
35
  "@atlaskit/util-service-support": "^7.2.0",
@@ -56,12 +56,19 @@
56
56
  }
57
57
  },
58
58
  "devDependencies": {
59
- "@atlaskit/adf-schema": "^56.7.0",
59
+ "@atlaskit/adf-schema": "^57.0.0",
60
60
  "@atlassian/a11y-jest-testing": "^0.15.0",
61
61
  "@atlassian/experiment-test-utils": "^0.2.0",
62
62
  "@atlassian/feature-flags-test-utils": "^1.2.0"
63
63
  },
64
64
  "platform-feature-flags": {
65
+ "platform_move_presence_agents": {
66
+ "type": "boolean",
67
+ "referenceOnly": true
68
+ },
69
+ "platform_editor_agentic_step_attribution": {
70
+ "type": "boolean"
71
+ },
65
72
  "platform-editor-presence-websocket-only": {
66
73
  "type": "boolean"
67
74
  },
@@ -70,6 +77,6 @@
70
77
  }
71
78
  },
72
79
  "peerDependencies": {
73
- "@atlaskit/editor-common": "^119.0.0"
80
+ "@atlaskit/editor-common": "^119.4.0"
74
81
  }
75
82
  }