Skip to content

feat(contact-center): add agent wellness breaks (WXCC-12423) - #741

Open
bhabalan wants to merge 8 commits into
webex:nextfrom
bhabalan:codex/wxcc-12423-wellness-widgets
Open

bhabalan wants to merge 8 commits into
webex:nextfrom
bhabalan:codex/wxcc-12423-wellness-widgets

Conversation

@bhabalan

@bhabalan bhabalan commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

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

  • bridges wellness feature enablement, agent-scoped notifications, user actions, and agent-state restoration through the MobX store; State Control V2 compatibility stays behind an internal first-party bridge
  • accepts valid wellness nudges for the current agent even when the notification agentSessionId differs
  • follows the SDK's identity-free public wellness contract: requestWellnessBreak() receives no arguments and respondToWellnessBreak({action}) receives no agent or session identity fields; the SDK owns the active registration and login/relogin context
  • adds Desktop-parity suggestion, direct-offer, denial, countdown, timed break, completion, toast, tooltip, audio, and metrics flows
  • preserves chronological wellness messages across close, minimize, reopen, and later events until the assistant Clear action is used
  • matches the Desktop assistant landing copy/icons and shows WellbeingBreak status with an elapsed timer during the break
  • restores the exact pre-break state, including legacy Idle auxiliary states such as Meeting, without echoing SDK-owned state transitions or exposing State Control V2 methods, events, store fields, hook inputs, or types to hosts
  • exposes wellnessBreakOverlayTarget for viewport, assistant-container, or custom-element rendering in React and Web Components
  • documents the feature contracts, adds generated-declaration guards for the store, AI Assistant, and aggregate widget packages, and retains internal legacy/V2 unit coverage

The 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-center build containing WXCC-12423; the repository currently pins 3.12.0-next.109, which predates that surface.

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Tooling change
  • Internal code refactor

The following scenarios were tested

  • The testing is done with the amplify link
  • Full repository pre-commit unit suite passed locally against the matching SDK worktree
  • @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 tests
  • Store, AI Assistant, and CC Widgets builds passed; generated widget declarations contain no State Control V2 public symbols
  • Store and AI Assistant lint passed

The repository-wide style check completed with zero errors and six existing sample-app warnings.

The GAI Coding Policy And Copyright Annotation Best Practices

  • GAI was not used (or, no additional notation is required)
  • Code was generated entirely by GAI
  • GAI was used to create a draft that was subsequently customized or modified
  • Coder created a draft manually that was non-substantively modified by GAI (e.g., refactoring was performed by GAI on manually written code)
  • Tool used for AI assistance (GitHub Copilot / Other - specify)
    • Github Copilot
    • Other - OpenAI Codex
  • This PR is related to
    • Feature
    • Defect fix
    • Tech Debt
    • Automation

Checklist before merging

  • I have not skipped any automated checks
  • All existing and new tests passed locally against the matching SDK worktree
  • I have updated the testing document
  • I have tested the functionality with amplify link

Make sure to have followed the contributing guidelines before submitting.

@bhabalan
bhabalan requested a review from a team as a code owner September 7, 2026 05:01
@bhabalan bhabalan added the validated Indicates that the PR is ready for actions label Sep 7, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 7, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-11T04:24:40.290361Z 44f7464 New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +328 to +329
? await import('./assets/WellnessBreakAnimationDark.json')
: await import('./assets/WellnessBreakAnimationLight.json');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +72 to +75
/** 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>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +1893 to +1896
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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +89 to +90
const legacyRecoveryCountRef = useRef(0);
const ascReconnectAttemptedRef = useRef(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@aws-amplify-us-east-2

Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-741.d1b38q61t1z947.amplifyapp.com

@github-actions github-actions Bot removed the validated Indicates that the PR is ready for actions label Sep 9, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +521 to +524
!this.store.isWellnessBreakEnabled ||
!payload?.agentSessionId ||
payload.agentId !== this.store.agentId ||
!WELLNESS_NOTIFICATION_ACTIONS.has(payload.actionEvent)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +583 to +587
await api.respondToWellnessBreak({
agentId: latest.agentId,
agentSessionId: latest.agentSessionId,
action: 'ACCEPTED',
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +1020 to +1023
void groups.reduce(
(sequence, group) =>
sequence.then(() =>
store.cc

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +942 to +946
capturedRef.current = {
stateModel: marker.stateModel,
theme: input.theme,
channelTypes: marker.channelTypes || [],
preBreakChannelStates: marker.preBreakChannelStates || {},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +851 to +855
if (input.rtdStatus.state === 'disconnected') {
clearOfferTimer();
if (phaseRef.current === 'offer-pending' || phaseRef.current === 'request-pending') {
setRequestAvailable(false);
setPhase('idle');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +203 to +207
.wellness-break-overlay--assistant,
.wellness-break-overlay--custom {
padding: 0;
position: absolute;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +25 to +27
fs.readdirSync(this.source)
.filter((filename) => filename.includes('lottie-web'))
.forEach((filename) => fs.copyFileSync(path.join(this.source, filename), path.join(this.destination, filename)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +724 to +726
if (phaseRef.current === 'request-pending') {
logWellnessMetric(WELLNESS_METRIC.PROVIDE_BREAK_EVENT_RECEIVED);
void enterBreak(event, false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@bhabalan bhabalan added the validated Indicates that the PR is ready for actions label Sep 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +35 to +36
const leaks = declarationRoots.flatMap((root) =>
collectDeclarations(root).flatMap((file) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +217 to +220
} catch {
runInAction(() => {
this.wellbeingBreakIdleCode = undefined;
this.wellnessBreakState = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +186 to +192
const clearHistory = useCallback(() => {
setHistory([]);
setContentCleared(true);
setRequestAvailable(false);
setNotice(undefined);
setError(undefined);
activeOfferHistoryIdRef.current = undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +791 to +795
if (settleTimerRef.current === undefined) {
settleTimerRef.current = window.setTimeout(() => {
settleTimerRef.current = undefined;
beginStartingCountdown();
}, WELLNESS_STATE_SETTLE_MS);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@github-actions github-actions Bot removed the validated Indicates that the PR is ready for actions label Sep 11, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +892 to +893
capturedRef.current = undefined;
clearRecoveryMarker();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +493 to +496
await api.requestWellnessBreak();
} catch {
setPhase('idle');
reportError('ACTION_REQUEST_FAILED', 'request-pending', true);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant