@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 +17 -0
- package/dist/cjs/participants/participants-service.js +40 -12
- package/dist/cjs/provider/commit-step.js +11 -2
- package/dist/cjs/version-wrapper.js +1 -1
- package/dist/es2019/participants/participants-service.js +38 -11
- package/dist/es2019/provider/commit-step.js +18 -5
- package/dist/es2019/version-wrapper.js +1 -1
- package/dist/esm/participants/participants-service.js +39 -11
- package/dist/esm/provider/commit-step.js +11 -2
- package/dist/esm/version-wrapper.js +1 -1
- package/dist/types/participants/participants-service.d.ts +6 -2
- package/dist/types/provider/commit-step.d.ts +1 -0
- package/package.json +13 -6
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
|
|
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
|
-
//
|
|
156
|
-
|
|
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
|
|
165
|
-
*
|
|
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
|
-
},
|
|
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
|
-
|
|
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 = "
|
|
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
|
|
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
|
-
//
|
|
144
|
-
|
|
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
|
|
153
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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,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
|
|
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
|
-
//
|
|
149
|
-
|
|
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
|
|
158
|
-
*
|
|
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
|
-
},
|
|
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
|
-
|
|
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
|
|
@@ -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
|
|
89
|
-
*
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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": "^
|
|
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.
|
|
80
|
+
"@atlaskit/editor-common": "^119.4.0"
|
|
74
81
|
}
|
|
75
82
|
}
|