-
Notifications
You must be signed in to change notification settings - Fork 384
fix(multi-party-conference): implement-multi-party-conference-feature #4520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Changes from all commits
c3a465b
356676b
7139c62
e280d93
9069beb
740e08a
943d728
99dbcf1
dda2829
98282e2
fcc7a2a
7301e9b
aebded3
80ddc86
8135ed8
329023c
ce038aa
4c4998a
941021f
3122eb9
6f6a452
be7b701
b101dec
6ea4f54
2b1f198
23ff75f
f37fb39
5a249f7
40bd1c5
9370463
5608057
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,12 @@ import LoggerProxy from '../../logger-proxy'; | |
import Task from '.'; | ||
import MetricsManager from '../../metrics/MetricsManager'; | ||
import {METRIC_EVENT_NAMES} from '../../metrics/constants'; | ||
import { | ||
checkParticipantNotInInteraction, | ||
getIsConferenceInProgress, | ||
isParticipantInMainInteraction, | ||
isPrimary, | ||
} from './TaskUtils'; | ||
|
||
/** @internal */ | ||
export default class TaskManager extends EventEmitter { | ||
|
@@ -128,8 +134,7 @@ export default class TaskManager extends EventEmitter { | |
{ | ||
...payload.data, | ||
wrapUpRequired: | ||
payload.data.interaction?.participants?.[payload.data.agentId]?.isWrapUp || | ||
false, | ||
payload.data.interaction?.participants?.[this.agentId]?.isWrapUp || false, | ||
}, | ||
this.wrapupData, | ||
this.agentId | ||
|
@@ -358,18 +363,55 @@ export default class TaskManager extends EventEmitter { | |
case CC_EVENTS.AGENT_CONSULT_CONFERENCE_ENDED: | ||
// Conference ended - update task state and emit event | ||
task = this.updateTaskData(task, payload.data); | ||
task.emit(TASK_EVENTS.TASK_CONFERENCE_ENDED, task); | ||
if ( | ||
!task || | ||
isPrimary(task, this.agentId) || | ||
isParticipantInMainInteraction(task, this.agentId) | ||
) { | ||
LoggerProxy.log('Primary or main interaction participant leaving conference'); | ||
} else { | ||
this.removeTaskFromCollection(task); | ||
} | ||
task?.emit(TASK_EVENTS.TASK_CONFERENCE_ENDED, task); | ||
break; | ||
case CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE: | ||
case CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE: { | ||
// Participant joined conference - update task state with participant information and emit event | ||
task = this.updateTaskData(task, payload.data); | ||
// Pre-calculate isConferenceInProgress with updated data to avoid double update | ||
const simulatedTaskForJoin = { | ||
...task, | ||
data: {...task.data, ...payload.data}, | ||
}; | ||
task = this.updateTaskData(task, { | ||
...payload.data, | ||
isConferenceInProgress: getIsConferenceInProgress(simulatedTaskForJoin), | ||
}); | ||
task.emit(TASK_EVENTS.TASK_PARTICIPANT_JOINED, task); | ||
break; | ||
case CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE: | ||
} | ||
case CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE: { | ||
// Conference ended - update task state and emit event | ||
task = this.updateTaskData(task, payload.data); | ||
// Pre-calculate isConferenceInProgress with updated data to avoid double update | ||
const simulatedTaskForLeft = { | ||
...task, | ||
data: {...task.data, ...payload.data}, | ||
}; | ||
task = this.updateTaskData(task, { | ||
...payload.data, | ||
isConferenceInProgress: getIsConferenceInProgress(simulatedTaskForLeft), | ||
}); | ||
if (checkParticipantNotInInteraction(task, this.agentId)) { | ||
if ( | ||
isParticipantInMainInteraction(task, this.agentId) || | ||
Comment on lines
+402
to
+404
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aren't these functions negation of each other? If Is my understanding correct here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The first one is to check whether it is an interaction or not. The second one is whether it is in main interaction(mediaObj.mType === 'mainCall') There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exactly. So, if the first one says that the participant is not in any interaction, they are definitely not in the main interaction. Right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a small difference of condition hasLeft in first method. This logic also we copied from Agent desktop. |
||
isPrimary(task, this.agentId) | ||
) { | ||
LoggerProxy.log('Primary or main interaction participant leaving conference'); | ||
} else { | ||
this.removeTaskFromCollection(task); | ||
} | ||
} | ||
task.emit(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task); | ||
break; | ||
} | ||
case CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE_FAILED: | ||
// Conference exit failed - update task state and emit failure event | ||
task = this.updateTaskData(task, payload.data); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* eslint-disable import/prefer-default-export */ | ||
import {ITask} from './types'; | ||
|
||
/** | ||
* Determines if the given agent is the primary agent (owner) of the task | ||
* @param task - The task to check | ||
* @param agentId - The agent ID to check for primary status | ||
* @returns true if the agent is the primary agent, false otherwise | ||
*/ | ||
export const isPrimary = (task: ITask, agentId: string): boolean => { | ||
if (!task?.data?.interaction?.owner) { | ||
// Fall back to checking data.agentId when owner is not set | ||
return task?.data?.agentId === agentId; | ||
} | ||
|
||
return task.data.interaction.owner === agentId; | ||
}; | ||
|
||
/** | ||
* Checks if the given agent is a participant in the main interaction (mainCall) | ||
* @param task - The task to check | ||
* @param agentId - The agent ID to check for participation | ||
* @returns true if the agent is a participant in the main interaction, false otherwise | ||
*/ | ||
export const isParticipantInMainInteraction = (task: ITask, agentId: string): boolean => { | ||
if (!task?.data?.interaction?.media) { | ||
return false; | ||
} | ||
|
||
return Object.values(task.data.interaction.media).some( | ||
(mediaObj: any) => mediaObj.mType === 'mainCall' && mediaObj.participants?.includes(agentId) | ||
); | ||
}; | ||
|
||
/** | ||
* Checks if the given agent is not in the interaction or has left the interaction | ||
* @param task - The task to check | ||
* @param agentId - The agent ID to check | ||
* @returns true if the agent is not in the interaction or has left, false otherwise | ||
*/ | ||
export const checkParticipantNotInInteraction = (task: ITask, agentId: string): boolean => { | ||
if (!task?.data?.interaction?.participants) { | ||
return true; | ||
} | ||
const {data} = task; | ||
|
||
return ( | ||
!(agentId in data.interaction.participants) || | ||
(agentId in data.interaction.participants && data.interaction.participants[agentId].hasLeft) | ||
mkesavan13 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
); | ||
}; | ||
|
||
/** | ||
* Gets the participant status for a given agent in a task | ||
* @param task - The task to check | ||
* @param agentId - The agent ID to get status for | ||
* @returns Object containing various status flags for the agent | ||
*/ | ||
export const getParticipantStatus = (task: ITask, agentId: string) => ({ | ||
isPrimary: isPrimary(task, agentId), | ||
isInMainInteraction: isParticipantInMainInteraction(task, agentId), | ||
isNotInInteraction: checkParticipantNotInInteraction(task, agentId), | ||
isOwner: task?.data?.interaction?.owner === agentId, | ||
hasLeft: task?.data?.interaction?.participants?.[agentId]?.hasLeft || false, | ||
}); | ||
|
||
/** | ||
* Determines if a conference is currently in progress based on the number of active agent participants | ||
* @param task - The task to check for conference status | ||
* @returns true if there are 2 or more active agent participants in the main call, false otherwise | ||
*/ | ||
export const getIsConferenceInProgress = (task: ITask): boolean => { | ||
const mediaMainCall = task?.data?.interaction?.media?.[task?.data?.interactionId]; | ||
const participantsInMainCall = new Set(mediaMainCall?.participants); | ||
const participants = task?.data?.interaction?.participants; | ||
|
||
const agentParticipants = new Set(); | ||
if (participantsInMainCall.size > 0) { | ||
participantsInMainCall.forEach((participantId: string) => { | ||
const participant = participants?.[participantId]; | ||
if ( | ||
participant && | ||
participant.pType !== 'Customer' && | ||
participant.pType !== 'Supervisor' && | ||
!participant.hasLeft && | ||
participant.pType !== 'VVA' | ||
) { | ||
agentParticipants.add(participantId); | ||
} | ||
}); | ||
} | ||
|
||
return agentParticipants.size >= 2; | ||
}; |
Uh oh!
There was an error while loading. Please reload this page.