@webex/contact-center 3.12.0-task-refactor.7 → 3.12.0-task-refactor.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/cc.js +3 -4
  2. package/dist/cc.js.map +1 -1
  3. package/dist/constants.js +1 -0
  4. package/dist/constants.js.map +1 -1
  5. package/dist/metrics/constants.js +2 -0
  6. package/dist/metrics/constants.js.map +1 -1
  7. package/dist/services/ApiAiAssistant.js +74 -3
  8. package/dist/services/ApiAiAssistant.js.map +1 -1
  9. package/dist/services/config/types.js +9 -1
  10. package/dist/services/config/types.js.map +1 -1
  11. package/dist/services/task/Task.js +32 -0
  12. package/dist/services/task/Task.js.map +1 -1
  13. package/dist/services/task/TaskManager.js +7 -2
  14. package/dist/services/task/TaskManager.js.map +1 -1
  15. package/dist/services/task/TaskUtils.js +3 -1
  16. package/dist/services/task/TaskUtils.js.map +1 -1
  17. package/dist/services/task/state-machine/TaskStateMachine.js +76 -0
  18. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
  19. package/dist/services/task/state-machine/actions.js +113 -23
  20. package/dist/services/task/state-machine/actions.js.map +1 -1
  21. package/dist/services/task/state-machine/uiControlsComputer.js +99 -21
  22. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
  23. package/dist/types/constants.d.ts +1 -0
  24. package/dist/types/metrics/constants.d.ts +2 -0
  25. package/dist/types/services/ApiAiAssistant.d.ts +10 -2
  26. package/dist/types/services/config/types.d.ts +16 -0
  27. package/dist/types/services/task/Task.d.ts +10 -0
  28. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +110 -0
  29. package/dist/types/services/task/state-machine/actions.d.ts +2 -0
  30. package/dist/types/types.d.ts +24 -0
  31. package/dist/types.js +15 -0
  32. package/dist/types.js.map +1 -1
  33. package/dist/webex.js +1 -1
  34. package/package.json +1 -1
  35. package/src/cc.ts +6 -4
  36. package/src/constants.ts +1 -0
  37. package/src/metrics/constants.ts +2 -0
  38. package/src/services/ApiAiAssistant.ts +102 -2
  39. package/src/services/config/types.ts +8 -0
  40. package/src/services/task/Task.ts +34 -0
  41. package/src/services/task/TaskManager.ts +7 -2
  42. package/src/services/task/TaskUtils.ts +5 -3
  43. package/src/services/task/ai-docs/AGENTS.md +7 -0
  44. package/src/services/task/ai-docs/ARCHITECTURE.md +12 -0
  45. package/src/services/task/state-machine/TaskStateMachine.ts +104 -0
  46. package/src/services/task/state-machine/actions.ts +151 -25
  47. package/src/services/task/state-machine/uiControlsComputer.ts +173 -30
  48. package/src/types.ts +25 -0
  49. package/test/unit/spec/cc.ts +2 -0
  50. package/test/unit/spec/services/ApiAiAssistant.ts +105 -17
  51. package/test/unit/spec/services/task/Task.ts +61 -0
  52. package/test/unit/spec/services/task/TaskManager.ts +42 -0
  53. package/test/unit/spec/services/task/TaskUtils.ts +65 -0
  54. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +676 -0
  55. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +597 -0
  56. package/test/unit/spec/services/task/voice/WebRTC.ts +99 -106
  57. package/umd/contact-center.min.js +2 -2
  58. package/umd/contact-center.min.js.map +1 -1
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.actions = void 0;
7
7
  exports.createInitialContext = createInitialContext;
8
+ exports.getTaskStateForUiControls = void 0;
8
9
  exports.updateUIControls = updateUIControls;
9
10
  var _xstate = require("xstate");
10
11
  var _constants = require("./constants");
@@ -59,8 +60,11 @@ const isActiveConsultState = (taskData, selfAgentId) => {
59
60
  if (selfAgentId) {
60
61
  const selfParticipant = taskData?.interaction?.participants?.[selfAgentId];
61
62
  const hasConsultMedia = Object.values(taskData?.interaction?.media ?? {}).some(media => media?.mType === _constants.MEDIA_TYPE_CONSULT);
62
- const isPendingOrActiveSelfConsult = selfParticipant?.consultState === _constants.CONSULT_STATE.CONSULTING || selfParticipant?.consultState === 'consultInitiated';
63
- if (isPendingOrActiveSelfConsult && hasConsultMedia && taskData?.isConsulted === false) {
63
+ // Pending consult before destination joins stays HELD, not CONSULTING.
64
+ if (selfParticipant?.consultState === 'consultInitiated' && !hasJoinedConsultDestination(taskData, selfAgentId) && hasConsultMedia && taskData?.isConsulted === false) {
65
+ return false;
66
+ }
67
+ if (selfParticipant?.consultState === _constants.CONSULT_STATE.CONSULTING && hasConsultMedia && taskData?.isConsulted === false) {
64
68
  return true;
65
69
  }
66
70
  }
@@ -76,13 +80,38 @@ const isSelfConsultingOrPending = (taskData, selfAgentId) => {
76
80
  const selfParticipant = taskData?.interaction?.participants?.[selfAgentId];
77
81
  return selfParticipant?.consultState === _constants.CONSULT_STATE.CONSULTING || selfParticipant?.consultState === 'consultInitiated';
78
82
  };
79
- const hasJoinedConsultDestination = taskData => {
83
+ const isDnOnConsultMedia = (taskData, selfAgentId) => {
84
+ if (!taskData?.interaction?.participants) return false;
85
+ const consultMedia = taskData.consultMediaResourceId ? taskData.interaction.media?.[taskData.consultMediaResourceId] : Object.values(taskData.interaction.media ?? {}).find(m => m?.mType === _constants.MEDIA_TYPE_CONSULT);
86
+ const consultParticipantIds = new Set(consultMedia?.participants ?? []);
87
+ if (consultParticipantIds.size === 0) return false;
88
+ return Object.values(taskData.interaction.participants).some(p => {
89
+ if (!p || p.hasLeft || p.id === selfAgentId) return false;
90
+ if (!consultParticipantIds.has(p.id)) return false;
91
+ const pType = String(p.pType ?? '').toUpperCase();
92
+ return pType === 'DN' || pType === 'EP-DN' || pType === 'EP_DN';
93
+ });
94
+ };
95
+ const mapConsultDestinationType = destinationType => {
96
+ if (!destinationType) return undefined;
97
+ const normalized = String(destinationType).toUpperCase();
98
+ if (normalized === 'DN' || normalized === 'EP-DN' || normalized === 'EP_DN') {
99
+ return 'entryPoint';
100
+ }
101
+ return destinationType;
102
+ };
103
+ const hasJoinedConsultDestination = (taskData, selfAgentId) => {
80
104
  if (!taskData?.interaction) return false;
81
105
  const participants = taskData.interaction.participants;
82
106
  const cpd = taskData.interaction.callProcessingDetails;
83
107
  const backendSaysJoined = cpd?.consultDestinationAgentJoined === 'true';
84
108
  if (backendSaysJoined) return true;
85
109
  if (!participants) return false;
110
+ const effectiveSelfAgentId = selfAgentId ?? taskData.agentId;
111
+ const selfParticipant = effectiveSelfAgentId ? participants[effectiveSelfAgentId] : undefined;
112
+ if (taskData.type === 'AgentConsulting' && selfParticipant?.consultState === _constants.CONSULT_STATE.CONSULTING && taskData.isConsulted === false && isDnOnConsultMedia(taskData, effectiveSelfAgentId)) {
113
+ return true;
114
+ }
86
115
  return Object.values(participants).some(p => {
87
116
  if (!p || p.isConsulted !== true || p.hasLeft) return false;
88
117
  return p.hasJoined === true || p.consultState === _constants.CONSULT_STATE.CONSULTING;
@@ -118,6 +147,7 @@ const getTaskStateForUiControls = (taskData, selfAgentId) => {
118
147
  }
119
148
  return _constants.TaskState.CONNECTED;
120
149
  };
150
+ exports.getTaskStateForUiControls = getTaskStateForUiControls;
121
151
  const deriveTaskDataUpdates = (context, taskData) => taskData ? (() => {
122
152
  const updates = {
123
153
  taskData,
@@ -134,10 +164,20 @@ const deriveTaskDataUpdates = (context, taskData) => taskData ? (() => {
134
164
  updates.consultDestinationAgentId = taskData.destAgentId;
135
165
  }
136
166
  }
167
+ const isConsultTerminalEvent = taskData.type === 'AgentConsultEnded' || taskData.type === 'AgentConsultFailed';
168
+ if (isConsultTerminalEvent) {
169
+ updates.consultInitiator = false;
170
+ updates.consultFromConference = false;
171
+ updates.consultDestinationAgentJoined = false;
172
+ updates.consultCallHeld = false;
173
+ updates.consultDestinationType = null;
174
+ updates.consultDestinationAgentId = null;
175
+ updates.transferConferenceRequested = false;
176
+ }
137
177
  if (consultingActive && taskData.destinationType) {
138
- updates.consultDestinationType = taskData.destinationType;
178
+ updates.consultDestinationType = mapConsultDestinationType(taskData.destinationType);
139
179
  }
140
- if (!context.consultInitiator) {
180
+ if (!isConsultTerminalEvent && !context.consultInitiator) {
141
181
  const consultInitiator = determineConsultInitiator(taskData, selfAgentId);
142
182
  if (consultInitiator !== undefined) {
143
183
  updates.consultInitiator = consultInitiator;
@@ -146,14 +186,24 @@ const deriveTaskDataUpdates = (context, taskData) => taskData ? (() => {
146
186
  }
147
187
  }
148
188
  const effectiveConsultInitiator = updates.consultInitiator ?? context.consultInitiator;
149
- if (effectiveConsultInitiator && conferenceFromPayload && (consultingActive || selfConsultingOrPending || Boolean(taskData?.consultMediaResourceId))) {
189
+ if (!isConsultTerminalEvent && effectiveConsultInitiator && conferenceFromPayload && (consultingActive || selfConsultingOrPending || Boolean(taskData?.consultMediaResourceId))) {
150
190
  updates.consultFromConference = true;
151
191
  }
152
- if (consultingActive && taskData.interaction) {
153
- const joinedConsultee = hasJoinedConsultDestination(taskData);
154
- if (joinedConsultee) updates.consultDestinationAgentJoined = true;
192
+ if (!isConsultTerminalEvent && (consultingActive || selfConsultingOrPending) && taskData.interaction) {
193
+ const joinedConsultee = hasJoinedConsultDestination(taskData, selfAgentId);
194
+ const selfParticipant = selfAgentId ? taskData.interaction.participants?.[selfAgentId] : undefined;
195
+ const agentConsultingSelfJoined = taskData.type === 'AgentConsulting' && effectiveConsultInitiator && selfParticipant?.consultState === _constants.CONSULT_STATE.CONSULTING;
196
+ if (joinedConsultee || agentConsultingSelfJoined) {
197
+ updates.consultDestinationAgentJoined = true;
198
+ } else if (selfParticipant?.consultState === 'consultInitiated') {
199
+ updates.consultDestinationAgentJoined = false;
200
+ }
155
201
  if (!context.consultDestinationType && !updates.consultDestinationType) {
156
- const hasEpDnParticipant = Boolean(taskData.interaction.participants && Object.values(taskData.interaction.participants).some(p => p?.pType === 'EP-DN' && !p?.hasLeft));
202
+ const hasEpDnParticipant = Boolean(taskData.interaction.participants && Object.values(taskData.interaction.participants).some(p => {
203
+ if (p?.hasLeft) return false;
204
+ const pType = String(p?.pType ?? '').toUpperCase();
205
+ return pType === 'EP-DN' || pType === 'EP_DN' || pType === 'DN';
206
+ }));
157
207
  if (hasEpDnParticipant) updates.consultDestinationType = 'entryPoint';
158
208
  }
159
209
  if (effectiveConsultInitiator) {
@@ -195,7 +245,7 @@ function updateUIControls(currentState) {
195
245
  return (0, _xstate.assign)(({
196
246
  context
197
247
  }) => ({
198
- uiControls: (0, _uiControlsComputer.computeUIControls)(currentState, context)
248
+ uiControls: (0, _uiControlsComputer.computeUIControls)(currentState, context, context.taskData ?? undefined)
199
249
  }));
200
250
  }
201
251
  const actions = exports.actions = {
@@ -248,9 +298,32 @@ const actions = exports.actions = {
248
298
  };
249
299
  return {};
250
300
  }),
251
- handleConsultFailed: (0, _xstate.assign)({
252
- consultDestinationAgentJoined: false,
253
- consultInitiator: false
301
+ handleConsultFailed: (0, _xstate.assign)(({
302
+ context,
303
+ event
304
+ }) => {
305
+ const taskData = getTaskDataFromEvent(event) ?? context.taskData;
306
+ const cleared = {
307
+ consultDestinationType: null,
308
+ consultDestinationAgentId: null,
309
+ consultDestinationAgentJoined: false,
310
+ consultInitiator: false,
311
+ exitingConference: false,
312
+ consultCallHeld: false,
313
+ consultFromConference: false,
314
+ transferConferenceRequested: false
315
+ };
316
+ const selfAgentId = context.uiControlConfig.agentId ?? taskData?.agentId;
317
+ const nextContext = {
318
+ ...context,
319
+ ...cleared,
320
+ taskData
321
+ };
322
+ const inferredState = getTaskStateForUiControls(taskData, selfAgentId);
323
+ return {
324
+ ...cleared,
325
+ uiControls: (0, _uiControlsComputer.computeUIControls)(inferredState, nextContext, taskData)
326
+ };
254
327
  }),
255
328
  handleConferenceStarted: (0, _xstate.assign)({
256
329
  consultInitiator: false
@@ -316,15 +389,32 @@ const actions = exports.actions = {
316
389
  }
317
390
  return {};
318
391
  }),
319
- clearConsultState: (0, _xstate.assign)({
320
- consultDestinationType: null,
321
- consultDestinationAgentId: null,
322
- consultDestinationAgentJoined: false,
323
- consultInitiator: false,
324
- exitingConference: false,
325
- consultCallHeld: false,
326
- consultFromConference: false,
327
- transferConferenceRequested: false
392
+ clearConsultState: (0, _xstate.assign)(({
393
+ context,
394
+ event
395
+ }) => {
396
+ const cleared = {
397
+ consultDestinationType: null,
398
+ consultDestinationAgentId: null,
399
+ consultDestinationAgentJoined: false,
400
+ consultInitiator: false,
401
+ exitingConference: false,
402
+ consultCallHeld: false,
403
+ consultFromConference: false,
404
+ transferConferenceRequested: false
405
+ };
406
+ const taskData = context.taskData ?? getTaskDataFromEvent(event);
407
+ const selfAgentId = context.uiControlConfig.agentId ?? taskData?.agentId;
408
+ const nextContext = {
409
+ ...context,
410
+ ...cleared,
411
+ taskData
412
+ };
413
+ const inferredState = getTaskStateForUiControls(taskData, selfAgentId);
414
+ return {
415
+ ...cleared,
416
+ uiControls: (0, _uiControlsComputer.computeUIControls)(inferredState, nextContext, taskData)
417
+ };
328
418
  }),
329
419
  setTransferConferenceRequested: (0, _xstate.assign)({
330
420
  transferConferenceRequested: true
@@ -1 +1 @@
1
- {"version":3,"names":["_xstate","require","_constants","_uiControlsComputer","_TaskUtils","_guards","determineConsultInitiator","taskData","selfAgentId","undefined","consultingAgentId","isConsulted","deriveRecordingState","callProcessingDetails","interaction","update","recordingStarted","recordInProgress","isPaused","recordingControlsAvailable","recordingInProgress","isActiveConsultState","state","INTERACTION_STATE","CONSULTING","selfParticipant","participants","hasConsultMedia","Object","values","media","some","mType","MEDIA_TYPE_CONSULT","isPendingOrActiveSelfConsult","consultState","CONSULT_STATE","POST_CALL","isSelfConsultingOrPending","hasJoinedConsultDestination","cpd","backendSaysJoined","consultDestinationAgentJoined","p","hasLeft","hasJoined","deriveConsultCallHeldFromTaskData","eventType","type","consultMediaId","consultMediaResourceId","consultMedia","find","m","Boolean","isHold","getTaskStateForUiControls","TaskState","IDLE","isTerminated","WRAPPING_UP","CONFERENCE","getIsConferenceInProgress","CONFERENCING","mainMediaId","mainInteractionId","interactionId","isMainHeld","HELD","CONNECTED","deriveTaskDataUpdates","context","updates","uiControlConfig","agentId","consultingActive","hasActiveConsultInPostCall","conferenceFromPayload","selfConsultingOrPending","inferredConsultingInitiator","destAgentId","isEpDnWithStoredId","consultDestinationType","consultDestinationAgentId","destinationType","consultInitiator","effectiveConsultInitiator","consultFromConference","joinedConsultee","hasEpDnParticipant","pType","consultCallHeld","nextContext","inferredState","uiControls","computeUIControls","getTaskDataFromEvent","event","createInitialContext","initialState","baseContext","exitingConference","transferConferenceRequested","getDefaultUIControls","updateUIControls","currentState","assign","actions","exports","initializeTask","updateTaskData","setConsultInitiator","TaskEvent","CONSULT","handleConsultFailed","handleConferenceStarted","setConsultDestination","destination","setConsultFromConference","forceConsultInitiator","setConsultAgentJoined","CONSULTING_ACTIVE","eventValue","setRecordingState","PAUSE_RECORDING","RESUME_RECORDING","clearConsultState","setTransferConferenceRequested","clearTransferConferenceRequested","setConsultCallHeld","clearConsultCallHeld","handleSwitchToMainCall","handleSwitchToConsult","handleConferenceFailed","handleParticipantLeft","setExitingConference","handleTransferConferenceSuccess","setHoldState","HOLD_SUCCESS","UNHOLD_SUCCESS","mediaResourceId","mediaEntry","updatedMedia","isConsultMedia","markEnded","requestAutoAnswer","requestCleanup","cleanupResources","emitTaskIncoming","emitTaskHydrate","emitTaskOfferContact","emitTaskAssigned","emitTaskHold","emitTaskResume","emitTaskEnd","emitTaskOfferConsult","emitTaskConsultCreated","emitTaskConsulting","emitTaskConsultAccepted","emitTaskConsultEnd","emitTaskReject","emitTaskWrapup","emitTaskRecordingStarted","emitTaskRecordingPaused","emitTaskRecordingResumed","emitTaskWrappedup","emitTaskParticipantLeft","emitTaskConferenceStarted","emitTaskConferenceEnded","emitTaskExitConference","emitTaskTransferConference","emitTaskSwitchCall","emitTaskConferenceFailed","emitTaskTransferConferenceFailed","emitTaskOutdialFailed"],"sources":["actions.ts"],"sourcesContent":["/**\n * Task State Machine Actions - Action implementations executed during state transitions\n */\n\nimport {assign} from 'xstate';\nimport {\n TaskContext,\n TaskEventPayload,\n UIControlConfig,\n TaskActionsMap,\n TaskActionArgs,\n RecordingStateUpdate,\n} from './types';\nimport {\n TaskEvent,\n TaskState,\n INTERACTION_STATE,\n CONSULT_STATE,\n MEDIA_TYPE_CONSULT,\n} from './constants';\nimport {DestinationType, TaskData} from '../types';\nimport {computeUIControls, getDefaultUIControls} from './uiControlsComputer';\nimport {getIsConferenceInProgress} from '../TaskUtils';\nimport {hasActiveConsultInPostCall} from './guards';\n\nconst determineConsultInitiator = (\n taskData: TaskData | undefined,\n selfAgentId: string | undefined\n): boolean | undefined => {\n if (!selfAgentId) return undefined;\n\n if (taskData?.consultingAgentId) {\n return taskData.consultingAgentId === selfAgentId;\n }\n\n if (taskData?.isConsulted === true) return false;\n\n return undefined;\n};\n\nconst deriveRecordingState = (taskData?: TaskData | null): RecordingStateUpdate => {\n const callProcessingDetails = taskData?.interaction?.callProcessingDetails;\n\n if (!callProcessingDetails) {\n return {};\n }\n\n const update: RecordingStateUpdate = {};\n const {recordingStarted, recordInProgress, isPaused} = callProcessingDetails as {\n recordingStarted?: boolean;\n recordInProgress?: boolean;\n isPaused?: boolean;\n };\n\n if (recordingStarted !== undefined) {\n update.recordingControlsAvailable = recordingStarted;\n if (!recordingStarted) {\n update.recordingInProgress = false;\n }\n }\n\n if (recordInProgress !== undefined) {\n update.recordingControlsAvailable = recordInProgress || recordingStarted || false;\n update.recordingInProgress = recordInProgress;\n }\n\n if (\n update.recordingControlsAvailable === undefined &&\n update.recordingInProgress === undefined &&\n recordingStarted\n ) {\n update.recordingControlsAvailable = true;\n update.recordingInProgress = true;\n }\n\n if (isPaused !== undefined) {\n update.recordingControlsAvailable = true;\n update.recordingInProgress = !isPaused;\n }\n\n return update;\n};\n\nconst isActiveConsultState = (taskData: TaskData | undefined, selfAgentId?: string): boolean => {\n if (taskData?.interaction?.state === INTERACTION_STATE.CONSULTING) return true;\n if (selfAgentId) {\n const selfParticipant = taskData?.interaction?.participants?.[selfAgentId] as any;\n const hasConsultMedia = Object.values(taskData?.interaction?.media ?? {}).some(\n (media: any) => media?.mType === MEDIA_TYPE_CONSULT\n );\n const isPendingOrActiveSelfConsult =\n selfParticipant?.consultState === CONSULT_STATE.CONSULTING ||\n selfParticipant?.consultState === 'consultInitiated';\n if (isPendingOrActiveSelfConsult && hasConsultMedia && taskData?.isConsulted === false) {\n return true;\n }\n }\n if (taskData?.interaction?.state === INTERACTION_STATE.POST_CALL && selfAgentId) {\n const selfParticipant = taskData.interaction?.participants?.[selfAgentId] as any;\n const hasConsultMedia = Object.values(taskData.interaction?.media ?? {}).some(\n (media: any) => media?.mType === MEDIA_TYPE_CONSULT\n );\n if (selfParticipant?.consultState === CONSULT_STATE.CONSULTING && hasConsultMedia) return true;\n }\n\n return false;\n};\n\nconst isSelfConsultingOrPending = (\n taskData: TaskData | undefined,\n selfAgentId?: string\n): boolean => {\n if (!taskData || !selfAgentId) return false;\n const selfParticipant = taskData?.interaction?.participants?.[selfAgentId] as any;\n\n return (\n selfParticipant?.consultState === CONSULT_STATE.CONSULTING ||\n selfParticipant?.consultState === 'consultInitiated'\n );\n};\n\nconst hasJoinedConsultDestination = (taskData: TaskData | undefined): boolean => {\n if (!taskData?.interaction) return false;\n const participants = taskData.interaction.participants as any;\n const cpd = taskData.interaction.callProcessingDetails as any;\n const backendSaysJoined = cpd?.consultDestinationAgentJoined === 'true';\n if (backendSaysJoined) return true;\n if (!participants) return false;\n\n return Object.values(participants).some((p: any) => {\n if (!p || p.isConsulted !== true || p.hasLeft) return false;\n\n return p.hasJoined === true || p.consultState === CONSULT_STATE.CONSULTING;\n });\n};\n\nconst deriveConsultCallHeldFromTaskData = (taskData: TaskData | undefined): boolean | undefined => {\n if (!taskData?.interaction) return undefined;\n\n const eventType = taskData.type;\n if (eventType === 'AgentContactHeld') return true;\n if (eventType === 'AgentContactUnheld') return false;\n\n const consultMediaId = taskData.consultMediaResourceId;\n\n const consultMedia: any = consultMediaId\n ? taskData.interaction.media?.[consultMediaId]\n : Object.values(taskData.interaction.media ?? {}).find(\n (m: any) => m?.mType === MEDIA_TYPE_CONSULT\n );\n\n if (!consultMedia) return undefined;\n\n return Boolean(consultMedia.isHold);\n};\n\nconst getTaskStateForUiControls = (\n taskData: TaskData | undefined,\n selfAgentId: string | undefined\n): TaskState => {\n if (!taskData?.interaction) {\n return TaskState.IDLE;\n }\n\n if (taskData.interaction.isTerminated === true) {\n return TaskState.WRAPPING_UP;\n }\n\n if (isActiveConsultState(taskData, selfAgentId)) {\n return TaskState.CONSULTING;\n }\n\n if (\n taskData.interaction.state === INTERACTION_STATE.CONFERENCE ||\n getIsConferenceInProgress(taskData)\n ) {\n return TaskState.CONFERENCING;\n }\n\n const mainMediaId = taskData.interaction.mainInteractionId || taskData.interactionId;\n const isMainHeld = Boolean(\n mainMediaId && taskData.interaction.media?.[mainMediaId]?.isHold === true\n );\n if (taskData.interaction.state === 'hold' || isMainHeld) {\n return TaskState.HELD;\n }\n\n return TaskState.CONNECTED;\n};\n\nconst deriveTaskDataUpdates = (context: TaskContext, taskData: TaskData | undefined) =>\n taskData\n ? (() => {\n const updates: Partial<TaskContext> = {\n taskData,\n ...deriveRecordingState(taskData),\n };\n\n const selfAgentId = context.uiControlConfig.agentId ?? taskData?.agentId;\n const consultingActive =\n isActiveConsultState(taskData, selfAgentId) ||\n hasActiveConsultInPostCall(taskData, selfAgentId);\n const conferenceFromPayload =\n taskData?.interaction?.state === INTERACTION_STATE.CONFERENCE ||\n getIsConferenceInProgress(taskData);\n const selfConsultingOrPending = isSelfConsultingOrPending(taskData, selfAgentId);\n const inferredConsultingInitiator =\n selfConsultingOrPending && taskData?.isConsulted === false;\n\n if (taskData.destAgentId) {\n const isEpDnWithStoredId =\n context.consultDestinationType === 'entryPoint' && context.consultDestinationAgentId;\n if (!isEpDnWithStoredId) {\n updates.consultDestinationAgentId = taskData.destAgentId;\n }\n }\n if (consultingActive && taskData.destinationType) {\n updates.consultDestinationType = taskData.destinationType as DestinationType;\n }\n\n if (!context.consultInitiator) {\n const consultInitiator = determineConsultInitiator(taskData, selfAgentId);\n if (consultInitiator !== undefined) {\n updates.consultInitiator = consultInitiator;\n } else if (\n inferredConsultingInitiator ||\n (consultingActive && taskData.isConsulted === false)\n ) {\n updates.consultInitiator = true;\n }\n }\n\n const effectiveConsultInitiator = updates.consultInitiator ?? context.consultInitiator;\n if (\n effectiveConsultInitiator &&\n conferenceFromPayload &&\n (consultingActive || selfConsultingOrPending || Boolean(taskData?.consultMediaResourceId))\n ) {\n updates.consultFromConference = true;\n }\n\n if (consultingActive && taskData.interaction) {\n const joinedConsultee = hasJoinedConsultDestination(taskData);\n if (joinedConsultee) updates.consultDestinationAgentJoined = true;\n\n if (!context.consultDestinationType && !updates.consultDestinationType) {\n const hasEpDnParticipant = Boolean(\n taskData.interaction.participants &&\n Object.values(taskData.interaction.participants).some(\n (p: any) => p?.pType === 'EP-DN' && !p?.hasLeft\n )\n );\n if (hasEpDnParticipant) updates.consultDestinationType = 'entryPoint' as any;\n }\n\n if (effectiveConsultInitiator) {\n const consultCallHeld = deriveConsultCallHeldFromTaskData(taskData);\n if (consultCallHeld !== undefined) {\n updates.consultCallHeld = consultCallHeld;\n }\n }\n }\n\n const nextContext = {\n ...context,\n ...updates,\n } as TaskContext;\n const inferredState = getTaskStateForUiControls(taskData, selfAgentId);\n\n updates.uiControls = computeUIControls(inferredState, nextContext, taskData);\n\n return updates;\n })()\n : {};\n\nconst getTaskDataFromEvent = (event?: TaskEventPayload): TaskData | undefined =>\n event && typeof event === 'object' ? (event as any).taskData : undefined;\n\nexport function createInitialContext(\n uiControlConfig: UIControlConfig,\n initialState: TaskState = TaskState.IDLE\n): TaskContext {\n const baseContext: TaskContext = {\n taskData: null,\n consultInitiator: false,\n exitingConference: false,\n consultFromConference: false,\n transferConferenceRequested: false,\n consultDestinationType: null,\n consultDestinationAgentId: null,\n consultDestinationAgentJoined: false,\n consultCallHeld: false,\n recordingControlsAvailable: false,\n recordingInProgress: false,\n uiControlConfig,\n uiControls: getDefaultUIControls(),\n };\n\n baseContext.uiControls = computeUIControls(initialState, baseContext);\n\n return baseContext;\n}\n\nexport function updateUIControls(currentState: TaskState) {\n return assign(({context}: TaskActionArgs) => ({\n uiControls: computeUIControls(currentState, context),\n }));\n}\n\nexport const actions: TaskActionsMap = {\n initializeTask: assign(({context, event}: {context: TaskContext; event: TaskEventPayload}) => {\n return {\n consultInitiator: false,\n exitingConference: false,\n consultDestinationType: null,\n consultDestinationAgentJoined: false,\n ...deriveTaskDataUpdates(context, getTaskDataFromEvent(event)),\n };\n }),\n\n /**\n * Update task data from ASSIGN event\n */\n updateTaskData: assign(({context, event}: TaskActionArgs) => {\n return deriveTaskDataUpdates(context, getTaskDataFromEvent(event));\n }),\n\n /**\n * Set consult initiator flag\n *\n * IMPORTANT: This action is called for CONSULT (user action) and CONSULT_CREATED (backend event).\n * For CONSULT (user action): The user explicitly clicked Consult, so they ARE the initiator.\n * For CONSULT_CREATED (backend event): Check taskData.isConsulted to determine if this agent\n * is the initiator. If isConsulted === true, this is Agent B (the consulted party), NOT the initiator.\n *\n * This prevents all agents in a conference from becoming consultInitiator when one agent\n * starts a new consult.\n */\n setConsultInitiator: assign(({event}: TaskActionArgs) => {\n const taskData = getTaskDataFromEvent(event);\n\n if (event.type === TaskEvent.CONSULT) return {consultInitiator: true};\n\n const selfAgentId = taskData?.agentId;\n const consultInitiator = determineConsultInitiator(taskData, selfAgentId);\n if (consultInitiator === true) return {consultInitiator: true};\n if (consultInitiator === false) return {consultInitiator: false};\n\n return {};\n }),\n\n handleConsultFailed: assign({consultDestinationAgentJoined: false, consultInitiator: false}),\n handleConferenceStarted: assign({consultInitiator: false}),\n\n setConsultDestination: assign(({event}: TaskActionArgs) => {\n if (!event || event.type !== TaskEvent.CONSULT) {\n return {};\n }\n\n const taskData = getTaskDataFromEvent(event);\n const consultDestinationType =\n 'destinationType' in event ? event.destinationType ?? null : null;\n const consultDestinationAgentId =\n ('destAgentId' in event ? event.destAgentId : null) ??\n ('destination' in event ? (event as any).destination : null) ??\n null;\n\n return {\n consultDestinationType,\n consultDestinationAgentId,\n consultDestinationAgentJoined: false,\n consultFromConference: false,\n taskData: {\n ...taskData,\n destAgentId: consultDestinationAgentId,\n },\n };\n }),\n\n setConsultFromConference: assign({consultFromConference: true}),\n\n forceConsultInitiator: assign({consultInitiator: true}),\n\n setConsultAgentJoined: assign(\n ({context, event}: {context: TaskContext; event: TaskEventPayload}) => {\n if (context.consultDestinationAgentJoined) {\n return {};\n }\n\n if (\n !event ||\n event.type !== TaskEvent.CONSULTING_ACTIVE ||\n !('consultDestinationAgentJoined' in event)\n ) {\n return {};\n }\n\n const eventValue = (event as {consultDestinationAgentJoined: boolean})\n .consultDestinationAgentJoined;\n\n return eventValue ? {consultDestinationAgentJoined: true} : {};\n }\n ),\n\n setRecordingState: assign(({event}: TaskActionArgs) => {\n if (!event || !('type' in event)) {\n return {};\n }\n\n if (event.type === TaskEvent.PAUSE_RECORDING) {\n return {\n recordingControlsAvailable: true,\n recordingInProgress: false,\n };\n }\n if (event.type === TaskEvent.RESUME_RECORDING) {\n return {\n recordingControlsAvailable: true,\n recordingInProgress: true,\n };\n }\n\n return {};\n }),\n\n clearConsultState: assign({\n consultDestinationType: null,\n consultDestinationAgentId: null,\n consultDestinationAgentJoined: false,\n consultInitiator: false,\n exitingConference: false,\n consultCallHeld: false,\n consultFromConference: false,\n transferConferenceRequested: false,\n }),\n\n setTransferConferenceRequested: assign({transferConferenceRequested: true}),\n clearTransferConferenceRequested: assign({transferConferenceRequested: false}),\n\n setConsultCallHeld: assign({consultCallHeld: true}),\n clearConsultCallHeld: assign({consultCallHeld: false}),\n handleSwitchToMainCall: assign({consultCallHeld: true}),\n handleSwitchToConsult: assign({consultCallHeld: false}),\n\n handleConferenceFailed: assign(({event}: TaskActionArgs) => {\n const taskData = getTaskDataFromEvent(event);\n\n return taskData ? {taskData} : {};\n }),\n handleParticipantLeft: assign(({event}: TaskActionArgs) => {\n const taskData = getTaskDataFromEvent(event);\n\n return taskData ? {taskData} : {};\n }),\n\n setExitingConference: assign({exitingConference: true}),\n\n handleTransferConferenceSuccess: assign(({event}: TaskActionArgs) => {\n const taskData = getTaskDataFromEvent(event);\n\n return taskData ? {taskData} : {};\n }),\n\n setHoldState: assign(({context, event}: TaskActionArgs) => {\n if (\n !event ||\n (event.type !== TaskEvent.HOLD_SUCCESS && event.type !== TaskEvent.UNHOLD_SUCCESS)\n ) {\n return {};\n }\n\n const mediaResourceId =\n 'mediaResourceId' in event\n ? (event as {mediaResourceId?: string}).mediaResourceId\n : undefined;\n\n if (!mediaResourceId) {\n return {};\n }\n\n const interaction = context.taskData?.interaction;\n const mediaEntry = interaction?.media?.[mediaResourceId];\n\n if (!interaction || !mediaEntry) {\n return {};\n }\n\n const updatedMedia = {\n ...interaction.media,\n [mediaResourceId]: {\n ...mediaEntry,\n isHold: event.type === TaskEvent.HOLD_SUCCESS,\n },\n };\n\n const updates: Partial<TaskContext> = {\n taskData: {\n ...(context.taskData as TaskData),\n interaction: {\n ...interaction,\n media: updatedMedia,\n },\n },\n };\n\n const consultMediaId = context.taskData?.consultMediaResourceId;\n const isConsultMedia = consultMediaId\n ? mediaResourceId === consultMediaId\n : mediaEntry?.mType === 'consult';\n\n if (isConsultMedia && context.consultInitiator) {\n updates.consultCallHeld = event.type === TaskEvent.HOLD_SUCCESS;\n }\n\n return updates;\n }),\n\n markEnded: assign(() => ({\n recordingControlsAvailable: false,\n recordingInProgress: false,\n })),\n\n requestAutoAnswer: () => undefined,\n requestCleanup: () => undefined,\n cleanupResources: () => undefined,\n\n // Event emitters - placeholders overridden by consumers\n emitTaskIncoming: () => undefined,\n emitTaskHydrate: () => undefined,\n emitTaskOfferContact: () => undefined,\n emitTaskAssigned: () => undefined,\n emitTaskHold: () => undefined,\n emitTaskResume: () => undefined,\n emitTaskEnd: () => undefined,\n emitTaskOfferConsult: () => undefined,\n emitTaskConsultCreated: () => undefined,\n emitTaskConsulting: () => undefined,\n emitTaskConsultAccepted: () => undefined,\n emitTaskConsultEnd: () => undefined,\n emitTaskReject: () => undefined,\n emitTaskWrapup: () => undefined,\n emitTaskRecordingStarted: () => undefined,\n emitTaskRecordingPaused: () => undefined,\n emitTaskRecordingResumed: () => undefined,\n emitTaskWrappedup: () => undefined,\n emitTaskParticipantLeft: () => undefined,\n emitTaskConferenceStarted: () => undefined,\n emitTaskConferenceEnded: () => undefined,\n emitTaskExitConference: () => undefined,\n emitTaskTransferConference: () => undefined,\n emitTaskSwitchCall: () => undefined,\n emitTaskConferenceFailed: () => undefined,\n emitTaskTransferConferenceFailed: () => undefined,\n emitTaskOutdialFailed: () => undefined,\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_xstate","require","_constants","_uiControlsComputer","_TaskUtils","_guards","determineConsultInitiator","taskData","selfAgentId","undefined","consultingAgentId","isConsulted","deriveRecordingState","callProcessingDetails","interaction","update","recordingStarted","recordInProgress","isPaused","recordingControlsAvailable","recordingInProgress","isActiveConsultState","state","INTERACTION_STATE","CONSULTING","selfParticipant","participants","hasConsultMedia","Object","values","media","some","mType","MEDIA_TYPE_CONSULT","consultState","hasJoinedConsultDestination","CONSULT_STATE","POST_CALL","isSelfConsultingOrPending","isDnOnConsultMedia","consultMedia","consultMediaResourceId","find","m","consultParticipantIds","Set","size","p","hasLeft","id","has","pType","String","toUpperCase","mapConsultDestinationType","destinationType","normalized","cpd","backendSaysJoined","consultDestinationAgentJoined","effectiveSelfAgentId","agentId","type","hasJoined","deriveConsultCallHeldFromTaskData","eventType","consultMediaId","Boolean","isHold","getTaskStateForUiControls","TaskState","IDLE","isTerminated","WRAPPING_UP","CONFERENCE","getIsConferenceInProgress","CONFERENCING","mainMediaId","mainInteractionId","interactionId","isMainHeld","HELD","CONNECTED","exports","deriveTaskDataUpdates","context","updates","uiControlConfig","consultingActive","hasActiveConsultInPostCall","conferenceFromPayload","selfConsultingOrPending","inferredConsultingInitiator","destAgentId","isEpDnWithStoredId","consultDestinationType","consultDestinationAgentId","isConsultTerminalEvent","consultInitiator","consultFromConference","consultCallHeld","transferConferenceRequested","effectiveConsultInitiator","joinedConsultee","agentConsultingSelfJoined","hasEpDnParticipant","nextContext","inferredState","uiControls","computeUIControls","getTaskDataFromEvent","event","createInitialContext","initialState","baseContext","exitingConference","getDefaultUIControls","updateUIControls","currentState","assign","actions","initializeTask","updateTaskData","setConsultInitiator","TaskEvent","CONSULT","handleConsultFailed","cleared","handleConferenceStarted","setConsultDestination","destination","setConsultFromConference","forceConsultInitiator","setConsultAgentJoined","CONSULTING_ACTIVE","eventValue","setRecordingState","PAUSE_RECORDING","RESUME_RECORDING","clearConsultState","setTransferConferenceRequested","clearTransferConferenceRequested","setConsultCallHeld","clearConsultCallHeld","handleSwitchToMainCall","handleSwitchToConsult","handleConferenceFailed","handleParticipantLeft","setExitingConference","handleTransferConferenceSuccess","setHoldState","HOLD_SUCCESS","UNHOLD_SUCCESS","mediaResourceId","mediaEntry","updatedMedia","isConsultMedia","markEnded","requestAutoAnswer","requestCleanup","cleanupResources","emitTaskIncoming","emitTaskHydrate","emitTaskOfferContact","emitTaskAssigned","emitTaskHold","emitTaskResume","emitTaskEnd","emitTaskOfferConsult","emitTaskConsultCreated","emitTaskConsulting","emitTaskConsultAccepted","emitTaskConsultEnd","emitTaskReject","emitTaskWrapup","emitTaskRecordingStarted","emitTaskRecordingPaused","emitTaskRecordingResumed","emitTaskWrappedup","emitTaskParticipantLeft","emitTaskConferenceStarted","emitTaskConferenceEnded","emitTaskExitConference","emitTaskTransferConference","emitTaskSwitchCall","emitTaskConferenceFailed","emitTaskTransferConferenceFailed","emitTaskOutdialFailed"],"sources":["actions.ts"],"sourcesContent":["/**\n * Task State Machine Actions - Action implementations executed during state transitions\n */\n\nimport {assign} from 'xstate';\nimport {\n TaskContext,\n TaskEventPayload,\n UIControlConfig,\n TaskActionsMap,\n TaskActionArgs,\n RecordingStateUpdate,\n} from './types';\nimport {\n TaskEvent,\n TaskState,\n INTERACTION_STATE,\n CONSULT_STATE,\n MEDIA_TYPE_CONSULT,\n} from './constants';\nimport {DestinationType, TaskData} from '../types';\nimport {computeUIControls, getDefaultUIControls} from './uiControlsComputer';\nimport {getIsConferenceInProgress} from '../TaskUtils';\nimport {hasActiveConsultInPostCall} from './guards';\n\nconst determineConsultInitiator = (\n taskData: TaskData | undefined,\n selfAgentId: string | undefined\n): boolean | undefined => {\n if (!selfAgentId) return undefined;\n\n if (taskData?.consultingAgentId) {\n return taskData.consultingAgentId === selfAgentId;\n }\n\n if (taskData?.isConsulted === true) return false;\n\n return undefined;\n};\n\nconst deriveRecordingState = (taskData?: TaskData | null): RecordingStateUpdate => {\n const callProcessingDetails = taskData?.interaction?.callProcessingDetails;\n\n if (!callProcessingDetails) {\n return {};\n }\n\n const update: RecordingStateUpdate = {};\n const {recordingStarted, recordInProgress, isPaused} = callProcessingDetails as {\n recordingStarted?: boolean;\n recordInProgress?: boolean;\n isPaused?: boolean;\n };\n\n if (recordingStarted !== undefined) {\n update.recordingControlsAvailable = recordingStarted;\n if (!recordingStarted) {\n update.recordingInProgress = false;\n }\n }\n\n if (recordInProgress !== undefined) {\n update.recordingControlsAvailable = recordInProgress || recordingStarted || false;\n update.recordingInProgress = recordInProgress;\n }\n\n if (\n update.recordingControlsAvailable === undefined &&\n update.recordingInProgress === undefined &&\n recordingStarted\n ) {\n update.recordingControlsAvailable = true;\n update.recordingInProgress = true;\n }\n\n if (isPaused !== undefined) {\n update.recordingControlsAvailable = true;\n update.recordingInProgress = !isPaused;\n }\n\n return update;\n};\n\nconst isActiveConsultState = (taskData: TaskData | undefined, selfAgentId?: string): boolean => {\n if (taskData?.interaction?.state === INTERACTION_STATE.CONSULTING) return true;\n if (selfAgentId) {\n const selfParticipant = taskData?.interaction?.participants?.[selfAgentId] as any;\n const hasConsultMedia = Object.values(taskData?.interaction?.media ?? {}).some(\n (media: any) => media?.mType === MEDIA_TYPE_CONSULT\n );\n // Pending consult before destination joins stays HELD, not CONSULTING.\n if (\n selfParticipant?.consultState === 'consultInitiated' &&\n !hasJoinedConsultDestination(taskData, selfAgentId) &&\n hasConsultMedia &&\n taskData?.isConsulted === false\n ) {\n return false;\n }\n if (\n selfParticipant?.consultState === CONSULT_STATE.CONSULTING &&\n hasConsultMedia &&\n taskData?.isConsulted === false\n ) {\n return true;\n }\n }\n if (taskData?.interaction?.state === INTERACTION_STATE.POST_CALL && selfAgentId) {\n const selfParticipant = taskData.interaction?.participants?.[selfAgentId] as any;\n const hasConsultMedia = Object.values(taskData.interaction?.media ?? {}).some(\n (media: any) => media?.mType === MEDIA_TYPE_CONSULT\n );\n if (selfParticipant?.consultState === CONSULT_STATE.CONSULTING && hasConsultMedia) return true;\n }\n\n return false;\n};\n\nconst isSelfConsultingOrPending = (\n taskData: TaskData | undefined,\n selfAgentId?: string\n): boolean => {\n if (!taskData || !selfAgentId) return false;\n const selfParticipant = taskData?.interaction?.participants?.[selfAgentId] as any;\n\n return (\n selfParticipant?.consultState === CONSULT_STATE.CONSULTING ||\n selfParticipant?.consultState === 'consultInitiated'\n );\n};\n\nconst isDnOnConsultMedia = (taskData: TaskData | undefined, selfAgentId?: string): boolean => {\n if (!taskData?.interaction?.participants) return false;\n\n const consultMedia: any = taskData.consultMediaResourceId\n ? taskData.interaction.media?.[taskData.consultMediaResourceId]\n : Object.values(taskData.interaction.media ?? {}).find(\n (m: any) => m?.mType === MEDIA_TYPE_CONSULT\n );\n const consultParticipantIds = new Set(consultMedia?.participants ?? []);\n if (consultParticipantIds.size === 0) return false;\n\n return Object.values(taskData.interaction.participants).some((p: any) => {\n if (!p || p.hasLeft || p.id === selfAgentId) return false;\n if (!consultParticipantIds.has(p.id)) return false;\n const pType = String(p.pType ?? '').toUpperCase();\n\n return pType === 'DN' || pType === 'EP-DN' || pType === 'EP_DN';\n });\n};\n\nconst mapConsultDestinationType = (\n destinationType: string | undefined\n): DestinationType | undefined => {\n if (!destinationType) return undefined;\n const normalized = String(destinationType).toUpperCase();\n if (normalized === 'DN' || normalized === 'EP-DN' || normalized === 'EP_DN') {\n return 'entryPoint' as DestinationType;\n }\n\n return destinationType as DestinationType;\n};\n\nconst hasJoinedConsultDestination = (\n taskData: TaskData | undefined,\n selfAgentId?: string\n): boolean => {\n if (!taskData?.interaction) return false;\n const participants = taskData.interaction.participants as any;\n const cpd = taskData.interaction.callProcessingDetails as any;\n const backendSaysJoined = cpd?.consultDestinationAgentJoined === 'true';\n if (backendSaysJoined) return true;\n if (!participants) return false;\n\n const effectiveSelfAgentId = selfAgentId ?? taskData.agentId;\n const selfParticipant = effectiveSelfAgentId\n ? (participants[effectiveSelfAgentId] as {consultState?: string} | undefined)\n : undefined;\n\n if (\n taskData.type === 'AgentConsulting' &&\n selfParticipant?.consultState === CONSULT_STATE.CONSULTING &&\n taskData.isConsulted === false &&\n isDnOnConsultMedia(taskData, effectiveSelfAgentId)\n ) {\n return true;\n }\n\n return Object.values(participants).some((p: any) => {\n if (!p || p.isConsulted !== true || p.hasLeft) return false;\n\n return p.hasJoined === true || p.consultState === CONSULT_STATE.CONSULTING;\n });\n};\n\nconst deriveConsultCallHeldFromTaskData = (taskData: TaskData | undefined): boolean | undefined => {\n if (!taskData?.interaction) return undefined;\n\n const eventType = taskData.type;\n if (eventType === 'AgentContactHeld') return true;\n if (eventType === 'AgentContactUnheld') return false;\n\n const consultMediaId = taskData.consultMediaResourceId;\n\n const consultMedia: any = consultMediaId\n ? taskData.interaction.media?.[consultMediaId]\n : Object.values(taskData.interaction.media ?? {}).find(\n (m: any) => m?.mType === MEDIA_TYPE_CONSULT\n );\n\n if (!consultMedia) return undefined;\n\n return Boolean(consultMedia.isHold);\n};\n\nexport const getTaskStateForUiControls = (\n taskData: TaskData | undefined,\n selfAgentId: string | undefined\n): TaskState => {\n if (!taskData?.interaction) {\n return TaskState.IDLE;\n }\n\n if (taskData.interaction.isTerminated === true) {\n return TaskState.WRAPPING_UP;\n }\n\n if (isActiveConsultState(taskData, selfAgentId)) {\n return TaskState.CONSULTING;\n }\n\n if (\n taskData.interaction.state === INTERACTION_STATE.CONFERENCE ||\n getIsConferenceInProgress(taskData)\n ) {\n return TaskState.CONFERENCING;\n }\n\n const mainMediaId = taskData.interaction.mainInteractionId || taskData.interactionId;\n const isMainHeld = Boolean(\n mainMediaId && taskData.interaction.media?.[mainMediaId]?.isHold === true\n );\n if (taskData.interaction.state === 'hold' || isMainHeld) {\n return TaskState.HELD;\n }\n\n return TaskState.CONNECTED;\n};\n\nconst deriveTaskDataUpdates = (context: TaskContext, taskData: TaskData | undefined) =>\n taskData\n ? (() => {\n const updates: Partial<TaskContext> = {\n taskData,\n ...deriveRecordingState(taskData),\n };\n\n const selfAgentId = context.uiControlConfig.agentId ?? taskData?.agentId;\n const consultingActive =\n isActiveConsultState(taskData, selfAgentId) ||\n hasActiveConsultInPostCall(taskData, selfAgentId);\n const conferenceFromPayload =\n taskData?.interaction?.state === INTERACTION_STATE.CONFERENCE ||\n getIsConferenceInProgress(taskData);\n const selfConsultingOrPending = isSelfConsultingOrPending(taskData, selfAgentId);\n const inferredConsultingInitiator =\n selfConsultingOrPending && taskData?.isConsulted === false;\n\n if (taskData.destAgentId) {\n const isEpDnWithStoredId =\n context.consultDestinationType === 'entryPoint' && context.consultDestinationAgentId;\n if (!isEpDnWithStoredId) {\n updates.consultDestinationAgentId = taskData.destAgentId;\n }\n }\n\n const isConsultTerminalEvent =\n taskData.type === 'AgentConsultEnded' || taskData.type === 'AgentConsultFailed';\n\n if (isConsultTerminalEvent) {\n updates.consultInitiator = false;\n updates.consultFromConference = false;\n updates.consultDestinationAgentJoined = false;\n updates.consultCallHeld = false;\n updates.consultDestinationType = null;\n updates.consultDestinationAgentId = null;\n updates.transferConferenceRequested = false;\n }\n\n if (consultingActive && taskData.destinationType) {\n updates.consultDestinationType = mapConsultDestinationType(taskData.destinationType);\n }\n\n if (!isConsultTerminalEvent && !context.consultInitiator) {\n const consultInitiator = determineConsultInitiator(taskData, selfAgentId);\n if (consultInitiator !== undefined) {\n updates.consultInitiator = consultInitiator;\n } else if (\n inferredConsultingInitiator ||\n (consultingActive && taskData.isConsulted === false)\n ) {\n updates.consultInitiator = true;\n }\n }\n\n const effectiveConsultInitiator = updates.consultInitiator ?? context.consultInitiator;\n if (\n !isConsultTerminalEvent &&\n effectiveConsultInitiator &&\n conferenceFromPayload &&\n (consultingActive || selfConsultingOrPending || Boolean(taskData?.consultMediaResourceId))\n ) {\n updates.consultFromConference = true;\n }\n\n if (\n !isConsultTerminalEvent &&\n (consultingActive || selfConsultingOrPending) &&\n taskData.interaction\n ) {\n const joinedConsultee = hasJoinedConsultDestination(taskData, selfAgentId);\n const selfParticipant = selfAgentId\n ? (taskData.interaction.participants?.[selfAgentId] as\n | {consultState?: string}\n | undefined)\n : undefined;\n const agentConsultingSelfJoined =\n taskData.type === 'AgentConsulting' &&\n effectiveConsultInitiator &&\n selfParticipant?.consultState === CONSULT_STATE.CONSULTING;\n\n if (joinedConsultee || agentConsultingSelfJoined) {\n updates.consultDestinationAgentJoined = true;\n } else if (selfParticipant?.consultState === 'consultInitiated') {\n updates.consultDestinationAgentJoined = false;\n }\n\n if (!context.consultDestinationType && !updates.consultDestinationType) {\n const hasEpDnParticipant = Boolean(\n taskData.interaction.participants &&\n Object.values(taskData.interaction.participants).some((p: any) => {\n if (p?.hasLeft) return false;\n const pType = String(p?.pType ?? '').toUpperCase();\n\n return pType === 'EP-DN' || pType === 'EP_DN' || pType === 'DN';\n })\n );\n if (hasEpDnParticipant) updates.consultDestinationType = 'entryPoint' as any;\n }\n\n if (effectiveConsultInitiator) {\n const consultCallHeld = deriveConsultCallHeldFromTaskData(taskData);\n if (consultCallHeld !== undefined) {\n updates.consultCallHeld = consultCallHeld;\n }\n }\n }\n\n const nextContext = {\n ...context,\n ...updates,\n } as TaskContext;\n const inferredState = getTaskStateForUiControls(taskData, selfAgentId);\n\n updates.uiControls = computeUIControls(inferredState, nextContext, taskData);\n\n return updates;\n })()\n : {};\n\nconst getTaskDataFromEvent = (event?: TaskEventPayload): TaskData | undefined =>\n event && typeof event === 'object' ? (event as any).taskData : undefined;\n\nexport function createInitialContext(\n uiControlConfig: UIControlConfig,\n initialState: TaskState = TaskState.IDLE\n): TaskContext {\n const baseContext: TaskContext = {\n taskData: null,\n consultInitiator: false,\n exitingConference: false,\n consultFromConference: false,\n transferConferenceRequested: false,\n consultDestinationType: null,\n consultDestinationAgentId: null,\n consultDestinationAgentJoined: false,\n consultCallHeld: false,\n recordingControlsAvailable: false,\n recordingInProgress: false,\n uiControlConfig,\n uiControls: getDefaultUIControls(),\n };\n\n baseContext.uiControls = computeUIControls(initialState, baseContext);\n\n return baseContext;\n}\n\nexport function updateUIControls(currentState: TaskState) {\n return assign(({context}: TaskActionArgs) => ({\n uiControls: computeUIControls(currentState, context, context.taskData ?? undefined),\n }));\n}\n\nexport const actions: TaskActionsMap = {\n initializeTask: assign(({context, event}: {context: TaskContext; event: TaskEventPayload}) => {\n return {\n consultInitiator: false,\n exitingConference: false,\n consultDestinationType: null,\n consultDestinationAgentJoined: false,\n ...deriveTaskDataUpdates(context, getTaskDataFromEvent(event)),\n };\n }),\n\n /**\n * Update task data from ASSIGN event\n */\n updateTaskData: assign(({context, event}: TaskActionArgs) => {\n return deriveTaskDataUpdates(context, getTaskDataFromEvent(event));\n }),\n\n /**\n * Set consult initiator flag\n *\n * IMPORTANT: This action is called for CONSULT (user action) and CONSULT_CREATED (backend event).\n * For CONSULT (user action): The user explicitly clicked Consult, so they ARE the initiator.\n * For CONSULT_CREATED (backend event): Check taskData.isConsulted to determine if this agent\n * is the initiator. If isConsulted === true, this is Agent B (the consulted party), NOT the initiator.\n *\n * This prevents all agents in a conference from becoming consultInitiator when one agent\n * starts a new consult.\n */\n setConsultInitiator: assign(({event}: TaskActionArgs) => {\n const taskData = getTaskDataFromEvent(event);\n\n if (event.type === TaskEvent.CONSULT) return {consultInitiator: true};\n\n const selfAgentId = taskData?.agentId;\n const consultInitiator = determineConsultInitiator(taskData, selfAgentId);\n if (consultInitiator === true) return {consultInitiator: true};\n if (consultInitiator === false) return {consultInitiator: false};\n\n return {};\n }),\n\n handleConsultFailed: assign(({context, event}: TaskActionArgs) => {\n const taskData = getTaskDataFromEvent(event) ?? context.taskData;\n const cleared = {\n consultDestinationType: null,\n consultDestinationAgentId: null,\n consultDestinationAgentJoined: false,\n consultInitiator: false,\n exitingConference: false,\n consultCallHeld: false,\n consultFromConference: false,\n transferConferenceRequested: false,\n };\n const selfAgentId = context.uiControlConfig.agentId ?? taskData?.agentId;\n const nextContext = {...context, ...cleared, taskData} as TaskContext;\n const inferredState = getTaskStateForUiControls(taskData, selfAgentId);\n\n return {\n ...cleared,\n uiControls: computeUIControls(inferredState, nextContext, taskData),\n };\n }),\n handleConferenceStarted: assign({consultInitiator: false}),\n\n setConsultDestination: assign(({event}: TaskActionArgs) => {\n if (!event || event.type !== TaskEvent.CONSULT) {\n return {};\n }\n\n const taskData = getTaskDataFromEvent(event);\n const consultDestinationType =\n 'destinationType' in event ? event.destinationType ?? null : null;\n const consultDestinationAgentId =\n ('destAgentId' in event ? event.destAgentId : null) ??\n ('destination' in event ? (event as any).destination : null) ??\n null;\n\n return {\n consultDestinationType,\n consultDestinationAgentId,\n consultDestinationAgentJoined: false,\n consultFromConference: false,\n taskData: {\n ...taskData,\n destAgentId: consultDestinationAgentId,\n },\n };\n }),\n\n setConsultFromConference: assign({consultFromConference: true}),\n\n forceConsultInitiator: assign({consultInitiator: true}),\n\n setConsultAgentJoined: assign(\n ({context, event}: {context: TaskContext; event: TaskEventPayload}) => {\n if (context.consultDestinationAgentJoined) {\n return {};\n }\n\n if (\n !event ||\n event.type !== TaskEvent.CONSULTING_ACTIVE ||\n !('consultDestinationAgentJoined' in event)\n ) {\n return {};\n }\n\n const eventValue = (event as {consultDestinationAgentJoined: boolean})\n .consultDestinationAgentJoined;\n\n return eventValue ? {consultDestinationAgentJoined: true} : {};\n }\n ),\n\n setRecordingState: assign(({event}: TaskActionArgs) => {\n if (!event || !('type' in event)) {\n return {};\n }\n\n if (event.type === TaskEvent.PAUSE_RECORDING) {\n return {\n recordingControlsAvailable: true,\n recordingInProgress: false,\n };\n }\n if (event.type === TaskEvent.RESUME_RECORDING) {\n return {\n recordingControlsAvailable: true,\n recordingInProgress: true,\n };\n }\n\n return {};\n }),\n\n clearConsultState: assign(({context, event}: TaskActionArgs) => {\n const cleared = {\n consultDestinationType: null,\n consultDestinationAgentId: null,\n consultDestinationAgentJoined: false,\n consultInitiator: false,\n exitingConference: false,\n consultCallHeld: false,\n consultFromConference: false,\n transferConferenceRequested: false,\n };\n const taskData = context.taskData ?? getTaskDataFromEvent(event);\n const selfAgentId = context.uiControlConfig.agentId ?? taskData?.agentId;\n const nextContext = {...context, ...cleared, taskData} as TaskContext;\n const inferredState = getTaskStateForUiControls(taskData, selfAgentId);\n\n return {\n ...cleared,\n uiControls: computeUIControls(inferredState, nextContext, taskData),\n };\n }),\n\n setTransferConferenceRequested: assign({transferConferenceRequested: true}),\n clearTransferConferenceRequested: assign({transferConferenceRequested: false}),\n\n setConsultCallHeld: assign({consultCallHeld: true}),\n clearConsultCallHeld: assign({consultCallHeld: false}),\n handleSwitchToMainCall: assign({consultCallHeld: true}),\n handleSwitchToConsult: assign({consultCallHeld: false}),\n\n handleConferenceFailed: assign(({event}: TaskActionArgs) => {\n const taskData = getTaskDataFromEvent(event);\n\n return taskData ? {taskData} : {};\n }),\n handleParticipantLeft: assign(({event}: TaskActionArgs) => {\n const taskData = getTaskDataFromEvent(event);\n\n return taskData ? {taskData} : {};\n }),\n\n setExitingConference: assign({exitingConference: true}),\n\n handleTransferConferenceSuccess: assign(({event}: TaskActionArgs) => {\n const taskData = getTaskDataFromEvent(event);\n\n return taskData ? {taskData} : {};\n }),\n\n setHoldState: assign(({context, event}: TaskActionArgs) => {\n if (\n !event ||\n (event.type !== TaskEvent.HOLD_SUCCESS && event.type !== TaskEvent.UNHOLD_SUCCESS)\n ) {\n return {};\n }\n\n const mediaResourceId =\n 'mediaResourceId' in event\n ? (event as {mediaResourceId?: string}).mediaResourceId\n : undefined;\n\n if (!mediaResourceId) {\n return {};\n }\n\n const interaction = context.taskData?.interaction;\n const mediaEntry = interaction?.media?.[mediaResourceId];\n\n if (!interaction || !mediaEntry) {\n return {};\n }\n\n const updatedMedia = {\n ...interaction.media,\n [mediaResourceId]: {\n ...mediaEntry,\n isHold: event.type === TaskEvent.HOLD_SUCCESS,\n },\n };\n\n const updates: Partial<TaskContext> = {\n taskData: {\n ...(context.taskData as TaskData),\n interaction: {\n ...interaction,\n media: updatedMedia,\n },\n },\n };\n\n const consultMediaId = context.taskData?.consultMediaResourceId;\n const isConsultMedia = consultMediaId\n ? mediaResourceId === consultMediaId\n : mediaEntry?.mType === 'consult';\n\n if (isConsultMedia && context.consultInitiator) {\n updates.consultCallHeld = event.type === TaskEvent.HOLD_SUCCESS;\n }\n\n return updates;\n }),\n\n markEnded: assign(() => ({\n recordingControlsAvailable: false,\n recordingInProgress: false,\n })),\n\n requestAutoAnswer: () => undefined,\n requestCleanup: () => undefined,\n cleanupResources: () => undefined,\n\n // Event emitters - placeholders overridden by consumers\n emitTaskIncoming: () => undefined,\n emitTaskHydrate: () => undefined,\n emitTaskOfferContact: () => undefined,\n emitTaskAssigned: () => undefined,\n emitTaskHold: () => undefined,\n emitTaskResume: () => undefined,\n emitTaskEnd: () => undefined,\n emitTaskOfferConsult: () => undefined,\n emitTaskConsultCreated: () => undefined,\n emitTaskConsulting: () => undefined,\n emitTaskConsultAccepted: () => undefined,\n emitTaskConsultEnd: () => undefined,\n emitTaskReject: () => undefined,\n emitTaskWrapup: () => undefined,\n emitTaskRecordingStarted: () => undefined,\n emitTaskRecordingPaused: () => undefined,\n emitTaskRecordingResumed: () => undefined,\n emitTaskWrappedup: () => undefined,\n emitTaskParticipantLeft: () => undefined,\n emitTaskConferenceStarted: () => undefined,\n emitTaskConferenceEnded: () => undefined,\n emitTaskExitConference: () => undefined,\n emitTaskTransferConference: () => undefined,\n emitTaskSwitchCall: () => undefined,\n emitTaskConferenceFailed: () => undefined,\n emitTaskTransferConferenceFailed: () => undefined,\n emitTaskOutdialFailed: () => undefined,\n};\n"],"mappings":"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","ignoreList":[]}
@@ -55,14 +55,23 @@ function createTaskUIControls(main, consult, activeLeg) {
55
55
  function getDefaultUIControls() {
56
56
  return createTaskUIControls(getDefaultInteractionUIControls(), getDefaultInteractionUIControls(), 'main');
57
57
  }
58
+
59
+ /** Consult media must exist on the interaction payload, not only as a stale resource id. */
60
+ function hasConsultMediaInInteraction(interaction, consultMediaResourceId) {
61
+ const media = interaction?.media ?? {};
62
+ const hasConsultLeg = Object.values(media).some(entry => entry?.mType === 'consult');
63
+ if (hasConsultLeg) return true;
64
+ if (!consultMediaResourceId) return false;
65
+ return Boolean(media[consultMediaResourceId]);
66
+ }
58
67
  function computeVoiceInteractionUIControls(state, context, config, fallbackTaskData, currentLeg = 'main') {
59
68
  // Early exit for idle
60
69
  if (state === _constants.TaskState.IDLE) {
61
70
  return getDefaultInteractionUIControls();
62
71
  }
63
72
 
64
- // Essential data
65
- const taskData = context.taskData ?? fallbackTaskData ?? null;
73
+ // Prefer live task.data (fallback) over stale state-machine snapshot during multi-login sync.
74
+ const taskData = fallbackTaskData ?? context.taskData ?? null;
66
75
  const interaction = taskData?.interaction;
67
76
  const mainCallId = interaction?.mainInteractionId || taskData?.interactionId;
68
77
  const isWebrtc = config.voiceVariant === _types.VOICE_VARIANT.WEBRTC;
@@ -95,7 +104,6 @@ function computeVoiceInteractionUIControls(state, context, config, fallbackTaskD
95
104
  // EP_DN consults are "ready" as soon as the consult is created (EP accepts routing immediately).
96
105
  // Backend sends destinationType as 'EP-DN'; SDK method uses 'entryPoint' — check both.
97
106
  const isEpDnConsult = consultDestinationType === 'entryPoint' || consultDestinationType === 'EP-DN';
98
- const isConsultDestinationReady = consultDestinationAgentJoined || isEpDnConsult;
99
107
  const stateImpliesHeld = state === _constants.TaskState.HELD || state === _constants.TaskState.RESUME_INITIATING;
100
108
  const stateImpliesConnected = state === _constants.TaskState.CONNECTED || state === _constants.TaskState.HOLD_INITIATING;
101
109
  const isHeld = stateImpliesHeld || serverHold === true;
@@ -109,22 +117,32 @@ function computeVoiceInteractionUIControls(state, context, config, fallbackTaskD
109
117
  const consultMedia = Object.values(interaction?.media ?? {}).find(media => media?.mediaResourceId === taskData?.consultMediaResourceId || media?.mType === 'consult');
110
118
  const selfParticipant = selfAgentId ? interaction?.participants?.[selfAgentId] : null;
111
119
  const selfInConsultCall = Boolean(selfAgentId) && Boolean(consultMedia?.participants?.includes(selfAgentId));
112
- const conferenceActive = isConferencing || conferenceFromBackend || consultFromConference;
120
+ const hasConsultMedia = hasConsultMediaInInteraction(interaction, taskData?.consultMediaResourceId);
121
+ const isConsultEndedForSelf = taskData?.type === 'AgentConsultEnded' || taskData?.type === 'AgentConsultFailed' || selfParticipant?.consultState === 'consultCompleted' && !hasConsultMedia && taskData?.isConsulted === false;
122
+ const effectiveConsultInitiator = isConsultEndedForSelf ? false : consultInitiator;
123
+ const effectiveConsultCallHeld = isConsultEndedForSelf ? false : consultCallHeld;
124
+ const effectiveConsultFromConference = isConsultEndedForSelf ? false : consultFromConference;
125
+ const effectiveConsultDestinationAgentJoined = isConsultEndedForSelf ? false : consultDestinationAgentJoined;
126
+ // After a consult ends for self, the backend stops sending consult media but the merged
127
+ // task.data can still carry the stale consult-media entry (reconcileData never deletes keys).
128
+ // Treat it as gone so post-consult main-leg controls (consult retry) are not blocked.
129
+ const effectiveHasConsultMedia = isConsultEndedForSelf ? false : hasConsultMedia;
130
+ const isConsultDestinationReady = effectiveConsultDestinationAgentJoined || isEpDnConsult;
131
+ const conferenceActive = isConferencing || conferenceFromBackend || effectiveConsultFromConference;
113
132
  // Treat consult initiator as "in conference" even if mainCall participant list lags while consulting.
114
- const inConference = conferenceActive && (isConferencing || selfInMainCall || consultInitiator);
133
+ const inConference = conferenceActive && (isConferencing || selfInMainCall || effectiveConsultInitiator);
115
134
 
116
135
  // Check if this is a consulted agent (must be after isConsulting is computed).
117
136
  const isSoleAgentOnCall = participantCount <= 1 && selfInMainCall && !isConsulting && !inConference;
118
- const isConsulted = inConference || isSoleAgentOnCall ? false : (0, _TaskUtils.getIsConsultedAgentForControls)(taskData, context, isConsulting) || !consultInitiator && (selfParticipant?.isConsulted === true || selfParticipant?.consultState === 'consulting');
137
+ const isConsulted = inConference || isSoleAgentOnCall ? false : (0, _TaskUtils.getIsConsultedAgentForControls)(taskData, context, isConsulting) || !effectiveConsultInitiator && (selfParticipant?.isConsulted === true || selfParticipant?.consultState === 'consulting');
119
138
 
120
139
  // Active call = can perform call operations
121
140
  const isActive = state === _constants.TaskState.CONNECTED || state === _constants.TaskState.HELD || state === _constants.TaskState.HOLD_INITIATING || state === _constants.TaskState.RESUME_INITIATING || isConsulting || isConferencing;
122
141
 
123
142
  // Consulted agents have limited controls until they're in conference or wrapup
124
143
  // Use inConference (not isConferencing) so controls remain enabled after state downgrade
125
- const hasFullControls = !isConsulted || consultInitiator || inConference || isWrappingUp;
126
- const consultOwnedBySelf = consultInitiator || Boolean(selfAgentId) && taskData?.consultingAgentId === selfAgentId;
127
- const hasConsultMedia = Boolean(taskData?.consultMediaResourceId || Object.values(interaction?.media ?? {}).some(media => media?.mType === 'consult'));
144
+ const hasFullControls = !isConsulted || effectiveConsultInitiator || inConference || isWrappingUp;
145
+ const consultOwnedBySelf = effectiveConsultInitiator || Boolean(selfAgentId) && taskData?.consultingAgentId === selfAgentId;
128
146
  const selfConsultPendingOnConsultMedia = selfParticipant?.consultState === 'consultInitiated' && !taskData?.isConsulted && hasConsultMedia;
129
147
  const ownerParticipant = interaction?.owner ? interaction.participants?.[interaction.owner] : undefined;
130
148
  const otherAgentConsultInProgress = Boolean(interaction?.participants && Object.values(interaction.participants).some(participant => {
@@ -133,12 +151,12 @@ function computeVoiceInteractionUIControls(state, context, config, fallbackTaskD
133
151
  if (participant.pType !== 'AGENT') return false;
134
152
  return participant.consultState === 'consultInitiated' || participant.consultState === 'consultReserved' || participant.consultState === 'consulting' || participant.currentState === 'consulting';
135
153
  }));
136
- const isHydratedConferenceConsultPending = inConference && selfConsultPendingOnConsultMedia && !consultDestinationAgentJoined;
137
- const hasParallelConsultLeg = consultOwnedBySelf && !isConsulting && !isConsulted && (consultInProgress || consultCallHeld || hasConsultMedia);
138
- const activeLegForConferenceConsult = consultCallHeld ? 'main' : 'consult';
154
+ const isHydratedConferenceConsultPending = inConference && selfConsultPendingOnConsultMedia && !effectiveConsultDestinationAgentJoined;
155
+ const hasParallelConsultLeg = !isConsultEndedForSelf && consultOwnedBySelf && !isConsulting && !isConsulted && (consultInProgress || effectiveConsultCallHeld || hasConsultMedia);
156
+ const activeLegForConferenceConsult = effectiveConsultCallHeld ? 'main' : 'consult';
139
157
  const isCurrentLegActive = currentLeg === activeLegForConferenceConsult;
140
- const isConferenceConsultTransferContext = inConference && consultInitiator && hasConsultMedia && isConsultDestinationReady;
141
- const consultLegOnHold = isConsulting && consultCallHeld;
158
+ const isConferenceConsultTransferContext = inConference && effectiveConsultInitiator && hasConsultMedia && isConsultDestinationReady;
159
+ const consultLegOnHold = isConsulting && effectiveConsultCallHeld;
142
160
  const callProcessingDetails = interaction?.callProcessingDetails;
143
161
  const conferenceHoldParticipant = callProcessingDetails?.conferenceHoldParticipant === true || callProcessingDetails?.conferenceHoldParticipant === 'true';
144
162
  const postDeclineHeldMainLeg = consultInitiator && !consultDestinationAgentJoined && isHeld && inConference && conferenceHoldParticipant;
@@ -152,6 +170,39 @@ function computeVoiceInteractionUIControls(state, context, config, fallbackTaskD
152
170
  const selfOnConsultLeg = selfParticipant?.consultState === 'consulting' || selfParticipant?.currentState === 'consulting';
153
171
  const showMainLegConferenceControlsDuringConsult = currentLeg === 'main' && inConference && consultInProgress && !selfOnConsultLeg;
154
172
  const allowHeldMainLegControlsForNonInitiator = showMainLegConferenceControlsDuringConsult && !isHydratedConferenceConsultPending;
173
+ const isConsultRequestedPhase = isConsultPendingBeforeJoin && !isConsulted && (consultInitiator || Boolean(selfAgentId) && selfParticipant?.consultState === 'consultInitiated' && taskData?.agentId === selfAgentId);
174
+ const isConsultUnansweredFailure = currentLeg === 'main' && !inConference && !taskData?.isConsulted && !effectiveHasConsultMedia && isHeld && selfParticipant?.consultState === 'consultCompleted' && (taskData?.type === 'AgentConsultFailed' || taskData?.type === 'AgentConsultEnded' || isConsultEndedForSelf);
175
+ if (isConsultUnansweredFailure) {
176
+ const recordingControl = recordingControlsAvailable && config.isRecordingEnabled && !inConference ? VISIBLE_ENABLED : DISABLED;
177
+ return {
178
+ ...getDefaultInteractionUIControls(),
179
+ hold: VISIBLE_ENABLED,
180
+ transfer: VISIBLE_ENABLED,
181
+ consult: VISIBLE_ENABLED,
182
+ recording: recordingControl,
183
+ end: VISIBLE_DISABLED
184
+ };
185
+ }
186
+ if (isConsultRequestedPhase) {
187
+ if (currentLeg === 'main') {
188
+ return {
189
+ ...getDefaultInteractionUIControls(),
190
+ transfer: VISIBLE_DISABLED,
191
+ conference: VISIBLE_DISABLED,
192
+ end: VISIBLE_DISABLED
193
+ };
194
+ }
195
+ if (currentLeg === 'consult') {
196
+ return {
197
+ ...getDefaultInteractionUIControls(),
198
+ endConsult: VISIBLE_ENABLED,
199
+ switch: VISIBLE_DISABLED,
200
+ transfer: VISIBLE_DISABLED,
201
+ transferConference: inConference ? VISIBLE_DISABLED : DISABLED,
202
+ mergeToConference: VISIBLE_DISABLED
203
+ };
204
+ }
205
+ }
155
206
  return {
156
207
  // Accept/Decline: Voice tasks in offered state
157
208
  // Desktop/WebRTC + inbound: accept enabled (agent manually accepts)
@@ -169,7 +220,7 @@ function computeVoiceInteractionUIControls(state, context, config, fallbackTaskD
169
220
  hold: (() => {
170
221
  if (!hasFullControls) return DISABLED;
171
222
  if (forceHeldPostConsultControls) return VISIBLE_ENABLED;
172
- if (consultOwnedBySelf && (isConsulting || hasParallelConsultLeg || consultCallHeld)) {
223
+ if (consultOwnedBySelf && (isConsulting || hasParallelConsultLeg || effectiveConsultCallHeld)) {
173
224
  return DISABLED;
174
225
  }
175
226
  if (hasParallelConsultLeg) return DISABLED;
@@ -186,7 +237,13 @@ function computeVoiceInteractionUIControls(state, context, config, fallbackTaskD
186
237
  if (!isWebrtc) return DISABLED;
187
238
  if (isWrappingUp) return DISABLED;
188
239
  if (currentLeg === 'consult' && !selfInConsultCall) return DISABLED;
189
- if ((isConsulting || hasParallelConsultLeg) && !isCurrentLegActive) return VISIBLE_DISABLED;
240
+ // The consulted agent has no separate consult leg; their main leg is the active call, so
241
+ // mute stays available while they consult (the heuristic below targets the initiator's
242
+ // inactive leg, not the consultee's only leg).
243
+ const isConsultedActiveMainLeg = isConsulted && currentLeg === 'main';
244
+ if ((isConsulting || hasParallelConsultLeg) && !isCurrentLegActive && !isConsultedActiveMainLeg) {
245
+ return VISIBLE_DISABLED;
246
+ }
190
247
  if (isConsulting) return VISIBLE_ENABLED;
191
248
  if (isConnected || isHeld || isConferencing) {
192
249
  if (inConference) return VISIBLE_ENABLED;
@@ -247,6 +304,13 @@ function computeVoiceInteractionUIControls(state, context, config, fallbackTaskD
247
304
  // Consult: connected/held/conference when conditions met
248
305
  consult: (() => {
249
306
  const isConnectedOrHeld = state === _constants.TaskState.CONNECTED || state === _constants.TaskState.HELD;
307
+ if (isHeld && !inConference && !effectiveHasConsultMedia && selfParticipant?.consultState === 'consultCompleted' && !taskData?.isConsulted) {
308
+ const canRetryConsult = !maxParticipants && customerPresent && !otherAgentConsultInProgress;
309
+ return {
310
+ isVisible: true,
311
+ isEnabled: canRetryConsult
312
+ };
313
+ }
250
314
  if (inConference && nonOwnerPostConsultCompletedHeldMainLeg) return VISIBLE_DISABLED;
251
315
  if (hasParallelConsultLeg) return DISABLED;
252
316
  if (!hasFullControls || !(isConnectedOrHeld || inConference)) {
@@ -405,23 +469,37 @@ function getVoiceLegState(currentState, context, config, fallbackTaskData) {
405
469
  consultState: _constants.TaskState.CONSULTING
406
470
  };
407
471
  }
408
- const taskData = context.taskData ?? fallbackTaskData ?? null;
472
+ const taskData = fallbackTaskData ?? context.taskData ?? null;
409
473
  const interaction = taskData?.interaction;
410
474
  const mainCallId = interaction?.mainInteractionId || taskData?.interactionId;
411
475
  const selfAgentId = config.agentId ?? taskData?.agentId;
476
+ const selfParticipant = selfAgentId ? interaction?.participants?.[selfAgentId] : null;
477
+ const hasConsultMedia = hasConsultMediaInInteraction(interaction, taskData?.consultMediaResourceId);
478
+ const isConsultEndedForSelf = taskData?.type === 'AgentConsultEnded' || taskData?.type === 'AgentConsultFailed' || selfParticipant?.consultState === 'consultCompleted' && !hasConsultMedia && taskData?.isConsulted === false;
412
479
  const consultInProgress = (0, _TaskUtils.getIsConsultInProgressForConferenceControls)(interaction, mainCallId, selfAgentId);
413
480
  const isConsultingState = currentState === _constants.TaskState.CONSULTING || currentState === _constants.TaskState.CONSULT_INITIATING || currentState === _constants.TaskState.CONF_INITIATING;
414
481
  const consultOwnedBySelf = context.consultInitiator || Boolean(selfAgentId) && taskData?.consultingAgentId === selfAgentId;
415
- const hasConsultMedia = Boolean(taskData?.consultMediaResourceId || Object.values(interaction?.media ?? {}).some(media => media?.mType === 'consult'));
416
- const selfParticipant = selfAgentId ? interaction?.participants?.[selfAgentId] : null;
417
482
  const selfConsultPendingOnConsultMedia = selfParticipant?.consultState === 'consultInitiated' && !taskData?.isConsulted && hasConsultMedia;
418
483
  const selfConsultingOnConsultMedia = selfParticipant?.consultState === 'consulting' && hasConsultMedia;
419
- const hasConsultLeg = Boolean(!interaction?.isTerminated && (consultOwnedBySelf && !taskData?.isConsulted || selfConsultingOnConsultMedia || selfConsultPendingOnConsultMedia) && (consultInProgress || isConsultingState || context.consultCallHeld || hasConsultMedia));
484
+ const isConsultUnansweredFailure = !taskData?.isConsulted && !hasConsultMedia && selfParticipant?.consultState === 'consultCompleted' && Boolean(mainCallId && taskData?.interaction?.media?.[mainCallId]?.isHold === true) && taskData?.interaction?.state !== 'conference' && !(0, _TaskUtils.getIsConferenceInProgress)(taskData);
485
+ const hasConsultLeg = Boolean(!isConsultEndedForSelf && !interaction?.isTerminated && !isConsultUnansweredFailure && (consultOwnedBySelf || selfConsultingOnConsultMedia || selfConsultPendingOnConsultMedia) && (consultInProgress || isConsultingState || context.consultCallHeld || hasConsultMedia));
420
486
  if (!hasConsultLeg) {
487
+ let mainState = currentState;
488
+ if (isConsultEndedForSelf && taskData?.interaction) {
489
+ const resolvedMainId = taskData.interaction.mainInteractionId || taskData.interactionId;
490
+ const isMainHeld = Boolean(resolvedMainId && taskData.interaction.media?.[resolvedMainId]?.isHold === true);
491
+ if (taskData.interaction.state === 'conference' || (0, _TaskUtils.getIsConferenceInProgress)(taskData)) {
492
+ mainState = _constants.TaskState.CONFERENCING;
493
+ } else if (isMainHeld || taskData.interaction.state === 'hold') {
494
+ mainState = _constants.TaskState.HELD;
495
+ } else {
496
+ mainState = _constants.TaskState.CONNECTED;
497
+ }
498
+ }
421
499
  return {
422
500
  hasConsultLeg: false,
423
501
  activeLeg: 'main',
424
- mainState: currentState,
502
+ mainState,
425
503
  consultState: _constants.TaskState.CONSULTING
426
504
  };
427
505
  }