Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6bf2b5296d
ℹ️ 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".
| ? await import('./assets/WellnessBreakAnimationDark.json') | ||
| : await import('./assets/WellnessBreakAnimationLight.json'); |
There was a problem hiding this comment.
Commit the imported wellness animations
Both literal dynamic imports reference files that are absent from the commit: a repo-wide git ls-tree -r 2feb787 search finds neither WellnessBreakAnimationDark.json nor WellnessBreakAnimationLight.json (and .gitignore currently ignores *.json). Webpack must resolve literal dynamic imports while building, so the AI Assistant and aggregate widget builds fail before the runtime catch can provide the intended media fallback; force-add the two approved JSON assets or remove/replace these imports.
Useful? React with 👍 / 👎.
| /** Returns the system-owned `WellbeingBreak` idle code for the active registration. */ | ||
| getWellbeingBreakIdleCode(): Promise<IdleCode>; | ||
| /** Changes one or more Agent State Control channels and resolves from the matching SDK event. */ | ||
| setAgentChannelState(data: SetAgentChannelStateParams): Promise<AgentChannelStateChangedEvent>; |
There was a problem hiding this comment.
Upgrade the SDK before calling wellness APIs
This commit leaves @webex/contact-center pinned to the pre-existing 3.12.0-next.109 build while locally extending IContactCenter with wellness APIs; the added feature intake explicitly identifies these declarations as temporary and requires replacing the SDK dependency and using its package-root types before release. Until that dependency is supplied, the type checker cannot verify these methods/events against the runtime SDK, and a missing getWellbeingBreakIdleCode disables wellness while a missing state/action API makes accepted breaks fail. Upgrade to the WXCC-12423 SDK surface rather than asserting it locally.
AGENTS.md reference: AGENTS.md:L56-L57
Useful? React with 👍 / 👎.
| ccSDK.off(CC_EVENTS.WELLNESS_BREAK, this.handleWellnessBreak); | ||
| ccSDK.off(CC_EVENTS.AI_ASSISTANT_RTD_STATUS_CHANGED, this.handleAIAssistantRtdStatus); | ||
| ccSDK.off(CC_EVENTS.AGENT_CHANNEL_RELOGIN_SUCCESS, this.handleAgentChannelRelogin); | ||
| ccSDK.off(CC_EVENTS.AGENT_CHANNEL_STATE_CHANGED, this.handleAgentChannelStateChanged); |
There was a problem hiding this comment.
Re-add wellness listeners after logout
After a normal logout, handleLogOut invokes removeEventListeners, and these lines detach all four registration-level wellness/ASC callbacks. On the next station login or DN registration in the same page, addEventListeners only restores the task and legacy-state callbacks; the wellness on(...) calls at the end of setupIncomingTaskHandler are not executed again. Consequently subsequent login sessions stop receiving wellness offers, RTD status, and channel-state updates until the store is initialized again.
Useful? React with 👍 / 👎.
| const legacyRecoveryCountRef = useRef(0); | ||
| const ascReconnectAttemptedRef = useRef(false); |
There was a problem hiding this comment.
Reset recovery retry guards for each break
These counters live for the entire mounted hook and are never reset when enterBreak initializes a new lifecycle. If one ASC break consumes its reconnect attempt and later succeeds, a restoration failure on a subsequent break cannot retry after relogin; likewise, once the five legacy background attempts have been consumed, later breaks receive no background recovery. Reset both refs when a new break is accepted so the documented retry bounds apply per break rather than per widget mount.
Useful? React with 👍 / 👎.
|
This pull request is automatically being deployed by Amplify Hosting (learn more). |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0cab52827a
ℹ️ 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".
| !this.store.isWellnessBreakEnabled || | ||
| !payload?.agentSessionId || | ||
| payload.agentId !== this.store.agentId || | ||
| !WELLNESS_NOTIFICATION_ACTIONS.has(payload.actionEvent) |
There was a problem hiding this comment.
Reject wellness events from other organizations
When the current profile has an organization ID, an SDK event with the same agentId but a different orgId passes this predicate and is exposed as an actionable offer. Accepting it then sends a response using the current tenant's local session, potentially acting on a foreign-organization notification; compare payload.orgId with this.store.agentProfile.orgId before storing the event.
Useful? React with 👍 / 👎.
| await api.respondToWellnessBreak({ | ||
| agentId: latest.agentId, | ||
| agentSessionId: latest.agentSessionId, | ||
| action: 'ACCEPTED', | ||
| }); |
There was a problem hiding this comment.
Abort acceptance when the active session rotates
If station relogin rotates agentSessionId while the preceding state-change request is pending, the session effect clears the old lifecycle, but this coroutine resumes with the latest snapshot captured before the await and sends ACCEPTED for the old session; it subsequently resurrects the old offer as waiting-for-safe-state in the new session. Capture an operation/session token before changing state and recheck it before responding, invoking callbacks, or advancing the phase.
Useful? React with 👍 / 👎.
| void groups.reduce( | ||
| (sequence, group) => | ||
| sequence.then(() => | ||
| store.cc |
There was a problem hiding this comment.
Continue restoring ASC groups after an unmount failure
When the widget unmounts during an ASC break with multiple restore groups, rejection of the first setAgentChannelState call rejects this .then chain, prevents every later group from running, and leaves the rejection unhandled. A transient failure restoring one channel can therefore leave all subsequent channels in WellbeingBreak; catch each group failure while preserving sequential execution so the remaining groups still receive a best-effort restore.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ece9358c66
ℹ️ 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".
| capturedRef.current = { | ||
| stateModel: marker.stateModel, | ||
| theme: input.theme, | ||
| channelTypes: marker.channelTypes || [], | ||
| preBreakChannelStates: marker.preBreakChannelStates || {}, |
There was a problem hiding this comment.
Preserve the legacy pre-break state across refresh recovery
When the page refreshes during a legacy break that began from an idle code such as Meeting, the recovery marker contains no preBreakLegacyState or preBreakLegacyAuxCodeId, and this reconstructed capture therefore leaves both undefined. performRestore() subsequently falls back to Available, making the agent routable instead of restoring the captured idle state. Persist and reconstruct the minimal legacy state fields alongside the ASC snapshot.
Useful? React with 👍 / 👎.
| if (input.rtdStatus.state === 'disconnected') { | ||
| clearOfferTimer(); | ||
| if (phaseRef.current === 'offer-pending' || phaseRef.current === 'request-pending') { | ||
| setRequestAvailable(false); | ||
| setPhase('idle'); |
There was a problem hiding this comment.
Deactivate the persisted offer on RTD disconnect
When RTD disconnects while an offer is pending, handleAIAssistantRtdStatus in storeEventsWrapper.ts has already changed the store phase to idle before this observer rerenders, so phaseRef.current is no longer offer-pending and this branch does not invalidate the offer history entry. The assistant then renders that persisted entry with enabled Take a break/Later actions, but both silently do nothing because the lifecycle is idle; resolve the active offer whenever the disconnect invalidates notification state.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e7d993a557
ℹ️ 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".
| // Wellness state is changed by the AI Assistant lifecycle. Reflect its | ||
| // SDK event (and the following restore event) without echoing either | ||
| // transition back through setAgentState. | ||
| if (isCurrentStateExternallyManaged || externallyManagedStateRef.current) { |
There was a problem hiding this comment.
Send manual selections made from the wellness state
When the User State dropdown currently shows WellbeingBreak, externallyManagedStateRef.current remains true and the dropdown is still interactive. If the agent selects another state, isCurrentStateExternallyManaged becomes false but this condition still takes the early return, so updateAgentState is never called: the widget displays the selected state while the backend remains in WellbeingBreak. Distinguish user-originated selections from SDK restoration events, or disable the selector while the wellness state is externally owned.
Useful? React with 👍 / 👎.
| .wellness-break-overlay--assistant, | ||
| .wellness-break-overlay--custom { | ||
| padding: 0; | ||
| position: absolute; | ||
| } |
There was a problem hiding this comment.
Size assistant overlays independently of closed chrome
With wellnessBreakOverlayTarget="assistant", accepting from the toast while the assistant is closed or minimized leaves the overlay absolutely positioned against an .ai-assistant root whose height is only the launcher or minimized bar. The 5/60/5 break surface is therefore squeezed into that small area instead of a usable assistant-sized canvas. Give the root a stable active-overlay size or open/target the full panel before rendering this mode.
Useful? React with 👍 / 👎.
| fs.readdirSync(this.source) | ||
| .filter((filename) => filename.includes('lottie-web')) | ||
| .forEach((filename) => fs.copyFileSync(path.join(this.source, filename), path.join(this.destination, filename))); |
There was a problem hiding this comment.
Copy the renderer chunk in production builds
Under NODE_ENV=production, Webpack gives the unnamed import('lottie-web') chunk a deterministic ID-based filename rather than a name containing lottie-web. This filter consequently copies no renderer chunk from cc-components/dist, while the embedded component runtime still requests that file; published AI Assistant and aggregate builds then report MEDIA_UNAVAILABLE and never render the animation. Copy the referenced wellness chunks without relying on their generated names, or assign the import an explicit chunk name.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b39210972e
ℹ️ 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 (phaseRef.current === 'request-pending') { | ||
| logWellnessMetric(WELLNESS_METRIC.PROVIDE_BREAK_EVENT_RECEIVED); | ||
| void enterBreak(event, false); |
There was a problem hiding this comment.
Elect one owner for singleton wellness events
When two AIAssistant widgets are mounted, both hook instances consume the same singleton-store sequence and can observe the same request-pending snapshot before either rerenders. A PROVIDE_WELLNESS_BREAK event therefore makes each instance call enterBreak, issuing duplicate setAgentState/setAgentChannelState requests and starting independent callbacks and timelines; direct offers similarly create one response timer per instance. Claim the event centrally or designate a single lifecycle owner before invoking enterBreak.
AGENTS.md reference: AGENTS.md:L87-L88
Useful? React with 👍 / 👎.
| </div> | ||
| ); | ||
|
|
||
| return overlayScope === 'custom' ? createPortal(overlay, resolvedTarget as HTMLElement) : overlay; |
There was a problem hiding this comment.
Portal viewport overlays outside the widget root
When the default viewport mode is used inside a transformed host container, returning the overlay inline makes its position: fixed box use that ancestor as its containing block and potentially inherit its clipping/stacking context. The purported viewport overlay can consequently cover only the embedded widget area rather than the browser viewport; portal viewport mode into the overlay's ownerDocument.body, while retaining the selected element for custom mode.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2208d08780
ℹ️ 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".
| const leaks = declarationRoots.flatMap((root) => | ||
| collectDeclarations(root).flatMap((file) => { |
There was a problem hiding this comment.
Restrict the API check to public declarations
This scans every emitted declaration under the store and AI Assistant packages, including intentionally internal source modules. The target tree explicitly emits names such as AgentChannelStateDetail, setAgentChannelState, UseWellnessBreakInput, and useWellnessBreak, so yarn workspace @webex/cc-widgets build always reaches a nonempty leaks array and throws; on a clean standalone build it can instead fail because the dependency dist roots do not exist. Traverse declarations reachable from each package's public entry point rather than all .d.ts files.
Useful? React with 👍 / 👎.
| } catch { | ||
| runInAction(() => { | ||
| this.wellbeingBreakIdleCode = undefined; | ||
| this.wellnessBreakState = { |
There was a problem hiding this comment.
Ignore stale wellness-code requests
If a code lookup from an earlier login/session rejects after logout, relogin, or a newer successful lookup, this unconditional catch clears the current session's valid wellbeingBreakIdleCode and replaces its lifecycle with SYSTEM_CODE_UNAVAILABLE. Since captureWellnessSession can start overlapping lookups, a transient failure from the older request can disable wellness for the newly active session; capture a request/session token and apply both success and failure only while it remains current.
Useful? React with 👍 / 👎.
| const clearHistory = useCallback(() => { | ||
| setHistory([]); | ||
| setContentCleared(true); | ||
| setRequestAvailable(false); | ||
| setNotice(undefined); | ||
| setError(undefined); | ||
| activeOfferHistoryIdRef.current = undefined; |
There was a problem hiding this comment.
Keep an active offer actionable after Clear
When the agent presses Clear while a direct offer is pending, setting contentCleared hides both the in-panel offer and its toast, while the lifecycle remains offer-pending and its timeout continues. The agent can no longer choose Take a break or Later and the backend eventually receives NO_RESPONSE; clear historical entries without hiding or discarding the currently actionable offer.
Useful? React with 👍 / 👎.
| if (settleTimerRef.current === undefined) { | ||
| settleTimerRef.current = window.setTimeout(() => { | ||
| settleTimerRef.current = undefined; | ||
| beginStartingCountdown(); | ||
| }, WELLNESS_STATE_SETTLE_MS); |
There was a problem hiding this comment.
Restart the settle window after any unsafe transition
Once this timer is armed, the !safe && phase === 'waiting-for-safe-state' case does not cancel it. If a task or unconfirmed channel appears during the two-second window and becomes safe again before the timer fires, the countdown begins using the original deadline rather than requiring two continuous safe seconds; clear settleTimerRef whenever safety is lost so each safe transition receives the full settling period.
Useful? React with 👍 / 👎.
…s' into codex/wxcc-12423-wellness-widgets
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 44f746414d
ℹ️ 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".
| capturedRef.current = undefined; | ||
| clearRecoveryMarker(); |
There was a problem hiding this comment.
Preserve recovery marker during initial session hydration
When the component mounts before login/relogin hydration, previousSessionRef initially contains an empty ID, so the first nonempty agentSessionId is treated as a rotation and deletes the refresh-recovery marker here. Because the recovery effect is declared later, it then finds no marker and cannot restore an agent who refreshed while still in WellbeingBreak, potentially leaving the agent unroutable; retain the marker across empty-to-current hydration and let its stored session ID determine whether it is stale.
Useful? React with 👍 / 👎.
| await api.requestWellnessBreak(); | ||
| } catch { | ||
| setPhase('idle'); | ||
| reportError('ACTION_REQUEST_FAILED', 'request-pending', true); |
There was a problem hiding this comment.
Ignore failures from superseded manual requests
If an agent logs out or relogs while requestWellnessBreak() is pending, a later rejection from that old request still executes this catch and changes the new session's global lifecycle to error. Depending on effect timing, the new session then shows either a stale ACTION_REQUEST_FAILED message or a blank wellness-owned body after its local error was cleared; capture the request's operation/session and ignore its completion after session rotation.
Useful? React with 👍 / 👎.
COMPLETES WXCC-12423
This pull request addresses
Adds Agent Wellness Break support to the React Contact Center widgets, aligned with the existing WXCC Desktop flows and the public Contact Center SDK contract in webex-js-sdk#5211.
VIDCAST: https://app.vidcast.io/share/2d163aaa-6444-49a5-82fd-861d360b59c3
by making the following changes
agentSessionIddiffersrequestWellnessBreak()receives no arguments andrespondToWellnessBreak({action})receives no agent or session identity fields; the SDK owns the active registration and login/relogin contextWellbeingBreakstatus with an elapsed timer during the breakwellnessBreakOverlayTargetfor viewport, assistant-container, or custom-element rendering in React and Web ComponentsThe local SDK link and sample-development package/webpack changes used during development are intentionally excluded. Runtime integration and remote CI require the published
@webex/contact-centerbuild containing WXCC-12423; the repository currently pins3.12.0-next.109, which predates that surface.Change Type
The following scenarios were tested
@webex/cc-store: 5 suites, 280 passing tests, 3 skipped tests@webex/cc-ai-assistant: 5 suites, 57 passing tests@webex/cc-components: 57 suites, 941 passing tests, 4 skipped tests, 234 snapshots@webex/cc-user-state: 2 suites, 26 passing testsThe repository-wide style check completed with zero errors and six existing sample-app warnings.
The GAI Coding Policy And Copyright Annotation Best Practices
Checklist before merging
Make sure to have followed the contributing guidelines before submitting.