fix(contact-center): consult flow fixes#4861
fix(contact-center): consult flow fixes#4861Kesari3008 wants to merge 12 commits intowebex:task-refactorfrom
Conversation
…tate for customer disconnect and consult failures with guard protection (webex#4841)" This reverts commit 3f6991c.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1e1d3b82e3
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| [TaskEvent.TASK_WRAPUP]: { | ||
| target: TaskState.TERMINATED, | ||
| actions: ['updateTaskData', 'markEnded', 'emitTaskEnd'], |
There was a problem hiding this comment.
Restore CONTACT_ENDED transition in OFFERED state
TaskManager.mapEventToTaskStateMachineEvent still maps CC_EVENTS.CONTACT_ENDED to TaskEvent.CONTACT_ENDED, but the OFFERED state now transitions on TASK_WRAPUP instead. In the pre-answer hangup path, CONTACT_ENDED is now unhandled, so the task can remain stuck in OFFERED (ringing UI persists, cleanup/end emission does not run).
Useful? React with 👍 / 👎.
| // This needs to be handled for all assign failed scenarios (contact, buddy) | ||
| // [AgentContactAssignFailed, AgentCtqFailed, AgentBlindTransferFailed, | ||
| // [AgentContactAssignFailed, AgentConsultFailed, AgentCtqFailed, AgentBlindTransferFailed, | ||
| // AgentVTeamTransferFailed, AgentConsultTransferFailed] | ||
| [TaskEvent.ASSIGN_FAILED]: { | ||
| target: TaskState.TERMINATED, |
There was a problem hiding this comment.
Handle CONSULT_FAILED while task is OFFERED
The mapping layer still emits TaskEvent.CONSULT_FAILED for AGENT_CONSULT_FAILED/AGENT_CTQ_FAILED, but OFFERED no longer has a CONSULT_FAILED transition. When a consulted agent declines or times out before assignment, that failure event is ignored and the incoming consult can remain stuck in OFFERED instead of terminating/clearing consult state.
Useful? React with 👍 / 👎.
|
|
||
| import './index'; | ||
|
|
||
| import config from './webex-config'; |
There was a problem hiding this comment.
Re-export index symbols from webex entrypoint
Removing export * from './index' from the package entrypoint drops runtime named exports (for example constants/classes exported in src/index.ts) even though the package types still point to dist/types/index.d.ts. Existing consumers importing named values from @webex/contact-center will compile against the declarations but fail at runtime because those exports are no longer present.
Useful? React with 👍 / 👎.
| @@ -1,4 +1,5 @@ | |||
| /* eslint-disable import/no-cycle */ | |||
| import EventEmitter from 'events'; | |||
There was a problem hiding this comment.
Keep ITask free of Node EventEmitter dependency
Changing ITask to extend EventEmitter introduces a public type dependency on 'events' (Node typings) and removes the previous lightweight emitter contract. This is a breaking type-surface change for browser-focused TypeScript consumers that do not include Node ambient types, causing declaration resolution errors unrelated to consult-flow behavior.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c36daee0b0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const response = await this.contact.unHold({ | ||
| interactionId: this.data.interactionId, | ||
| data: {mediaResourceId: consultMediaResourceId}, | ||
| data: {mediaResourceId: this.data.mediaResourceId}, | ||
| }); |
There was a problem hiding this comment.
Toggle both media legs when switching consult calls
In switchCall(), the consult→main path now only calls unHold on the main media and returns, while the main→consult path only calls hold on the main media; neither branch updates the consult media leg anymore. During active consult flows this can leave media hold states out of sync with consultCallHeld (e.g., both legs held or both unheld depending on backend behavior), so the SDK reports a switched leg while call control state is not actually switched.
Useful? React with 👍 / 👎.
| return { | ||
| main, | ||
| consult, | ||
| activeLeg, | ||
| }; |
There was a problem hiding this comment.
Preserve legacy flat uiControls fields for runtime consumers
This constructor now emits TaskUIControls as {main, consult, activeLeg} only, removing the previously shipped top-level fields like accept, hold, and transfer from the runtime payload. Existing JavaScript consumers listening to TASK_UI_CONTROLS_UPDATED and reading task.uiControls.accept will now get undefined and break at runtime, so this change introduces a backward-incompatible API regression unless legacy aliases are preserved.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 58b9fffc2b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const hasConsultLeg = Boolean( | ||
| consultOwnedBySelf && | ||
| !taskData?.isConsulted && | ||
| !interaction?.isTerminated && | ||
| (consultInProgress || isConsultingState || context.consultCallHeld || hasConsultMedia) |
There was a problem hiding this comment.
Ignore stale consult metadata when computing
hasConsultLeg
getVoiceLegState() treats hasConsultMedia alone as sufficient to keep a consult leg alive. If backend/task snapshots retain stale consultMediaResourceId or consult media entries after a consult has ended (a case this commit already acknowledges in other logic), this condition makes hasConsultLeg stay true, which then forces activeLeg to 'consult' and computes controls from consult states even though the call is no longer in consult flow. In practice, post-consult tasks can remain stuck showing consult controls and block normal connected-call actions until a later payload clears those stale fields.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 767f6b763f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Initiator already switched back to the main/customer leg | ||
| guard: ({context}) => | ||
| context.consultInitiator === true && context.consultCallHeld === true, | ||
| target: TaskState.CONNECTED, |
There was a problem hiding this comment.
Gate CONSULT_END transition on real hold state
This new branch promotes CONSULT_END to CONNECTED whenever consultCallHeld is true, but that flag is toggled optimistically by SWITCH_TO_MAIN_CALL before the unHold API succeeds. If AGENT_CONSULT_ENDED arrives before the unhold confirmation (or the unhold fails), the machine still moves to CONNECTED even though the primary leg can remain held, and the subsequent revert switch event is no longer handled outside CONSULTING. This leaves task state/UI out of sync with call media state; use backend hold data (like guards.isPrimaryMediaOnHold) when choosing between CONNECTED and HELD here.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 35b6e57895
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (isConsulting) { | ||
| if (!consultInitiator) return DISABLED; | ||
| if (consultLegOnHold) return VISIBLE_DISABLED; | ||
|
|
||
| return consultDestinationAgentJoined ? VISIBLE_ENABLED : VISIBLE_DISABLED; |
There was a problem hiding this comment.
Hide transfer while consulting from conference
The new isConsulting transfer branch bypasses the later inConference guard, so a consult started from an active conference (conferenceFromBackend/conference context) now shows the regular transfer control as available. In that scenario Voice.transfer() does not use the conference-transfer flow, so users can hit the wrong transfer path (often resulting in failed or incorrect transfer behavior) instead of using transferConference. Please keep transfer hidden/disabled for consult-from-conference states.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8939289465
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| taskData: { | ||
| ...taskData, | ||
| destAgentId: consultDestinationAgentId, | ||
| }, |
There was a problem hiding this comment.
Preserve existing taskData when setting consult destination
setConsultDestination now writes taskData using only the event payload, but TaskEvent.CONSULT events from Voice.consult() do not include taskData. In that path this assignment replaces context.taskData with a partial object ({destAgentId: ...}), dropping interaction/media fields that UI and guards depend on. If consult initiation then fails (CONSULT_FAILED is emitted without taskData), the machine returns to CONNECTED/HELD with truncated context, so controls are computed from incomplete data (for example consult can remain disabled) until a later websocket refresh. Avoid overwriting taskData when the event has no full snapshot, or merge into context.taskData instead.
Useful? React with 👍 / 👎.
COMPLETES # Consult flow fixes in task-refactor branch
This pull request addresses
Updating UIControls object structure and fixing small buttons visibility and enablement issues for consult flows.
by making the following changes
Updating UIControls object structure and fixing small buttons visibility and enablement issues for consult flows.
Issue Fixed:
Buttons not appearing for consult leg and main interaction.
Root Cause: We maintained UI controls object per task and when we have 2 logs created: main interaction and consult leg, there was no way to set different controls for each of these legs.
Fix:
Switch call didn't work on the first click, only from the second click, it actually worked.
Root Cause: This was happening due to reverse logic in switch call method. When switch is pressed on consult leg, we are supposed to trigger unHold the main interaction and consult leg is placed on hold automatically by backend. And when we press it on the main interaction, hold should be triggered to reverse it. We were doing the revrse of this by using consultMediaResourceID which wasn't working.
Fix: Updated the behavior to unhold and hold on main interaction media resource ID. This is in parity with Agent Desktop behavior as well,
Consult transfer kept failing with 400 Bad request due to destinationType being sent in payload as 'Agent' instead of 'agent'.
Fix: Updated the payload to make it lowercase in the API irrespective of what's being passed from client
Post switch call end consult action was causing hold/resume in wrong sequence or was using media resource ID.
Some more small fixes for displaying the controls for each leg and updating it correctly after every action.
Change Type
The following scenarios were tested
The GAI Coding Policy And Copyright Annotation Best Practices
I certified that
Make sure to have followed the contributing guidelines before submitting.