feat[contact-center]: Mid call and Post Call summaries - #5171
Conversation
In git worktrees created for Artificer tasks, node_modules and .husky/_/husky.sh are absent (gitignored, yarn install never runs). The prior fix conditionally sourced _/husky.sh but left the yarn commands running unconditionally, causing Abort trap: 6 via the broken Homebrew node 22.8.0 (ICU/icu4c@78 incompatibility). Change && (conditional source) to || exit 0 (hard gate): if _/husky.sh is absent the hook exits 0 immediately before any yarn call. In the main checkout _/husky.sh is present so hooks run normally.
# Conflicts: # packages/@webex/contact-center/src/index.ts # packages/@webex/contact-center/src/metrics/ai-docs/AGENTS.md # packages/@webex/contact-center/src/metrics/ai-docs/ARCHITECTURE.md # packages/@webex/contact-center/src/metrics/constants.ts # packages/@webex/contact-center/src/services/ApiAiAssistant.ts # packages/@webex/contact-center/src/services/agent/ai-docs/AGENTS.md # packages/@webex/contact-center/src/services/agent/ai-docs/ARCHITECTURE.md # packages/@webex/contact-center/src/services/task/TaskUtils.ts # packages/@webex/contact-center/src/services/task/ai-docs/ARCHITECTURE.md # packages/@webex/contact-center/test/unit/spec/services/ApiAiAssistant.ts
- metrics/ARCHITECTURE.md: correct AI summary metric names from AI_SUMMARY_POST/MID_CALL_REQUEST_* to AI_SUMMARY_GET_POST/MID_CALL_* to match actual constants.ts definitions - task-spec.md: add TASK_FEATURE_ENABLEMENT and TASK_MID_CALL_SUMMARY_FOR_RECEIVING_AGENT to TASK_EVENTS inventory (count 49 → 51); add agentName? as 7th param in createTask signatures Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
left a comment
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e0c51e5b5d
ℹ️ 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 wrapupInteractionId = currentTask?.data?.interactionId; | ||
| const wrapupSummaryFeatures = summaryFeatureMap.get(wrapupInteractionId) || {}; |
There was a problem hiding this comment.
Retain the wrapping task across the summary wait
When a post-call request is still pending after wrapup() succeeds, task:end can fire during this await and its listener clears currentTask and deletes the task's feature flags. The subsequent branches then either skip the required NOT_RECEIVED/IGNORED response or attempt sendPostCallSummaryResponse() on undefined or a newly selected task. Capture the task and its interaction/feature state before starting wrap-up and use that retained task for the response.
Useful? React with 👍 / 👎.
…eatureEnablement Task-level task:featureEnablement (TASK_EVENTS.TASK_FEATURE_ENABLEMENT) is now the canonical event for SDK consumers. Remove the cc:featureEnablement chain: - cc.ts: delete handleFeatureEnablement and its registration in refreshTaskManagerEventForwarders / runDeregisterCleanup - TaskManager.ts: drop the AGENT_EVENTS.FEATURE_ENABLEMENT emit from handleFeatureEnablementEvent (task-level emit and AISummaryCoordinator state update are preserved) - Remove FeatureEnablementEventPayload import from cc.ts (now unused) - Remove AGENT_EVENTS import from TaskManager.ts (now unused there) - Fix test/unit/spec/cc.ts: remove all assertions that verified the removed forwarding behaviour - Fix test/unit/spec/services/task/TaskManager.ts: strip listener setup and assertions for AGENT_EVENTS.FEATURE_ENABLEMENT from the affected tests; remove the now-unused AGENT_EVENTS import - Fix test/unit/spec/index.ts: add five UserPreference types exported by the upstream merge to EXPECTED_ROOT_EXPORTS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rictEqual Jest stores mock arguments in arrays created in the jest-mock host realm, while test expectations run in the jest sandbox realm. These have different Array.prototype objects, so typeEquality() sees mismatched constructors and returns false — causing toStrictEqual to fail even though the content is identical (hence "serializes to the same string"). Fix: compare the transport payload directly via mock.calls[0][1] rather than wrapping the whole calls array in toStrictEqual. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
left a comment
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 12dd0d809a
ℹ️ 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".
| /** Emitted when AI summary feature enablement changes for an interaction */ | ||
| FEATURE_ENABLEMENT = 'cc:featureEnablement', |
There was a problem hiding this comment.
Remove the feature event that is never emitted
When a consumer subscribes to the exported AGENT_EVENTS.FEATURE_ENABLEMENT event on the Contact Center instance, it will never fire: a package-wide source search finds no cc:featureEnablement emission, while TaskManager emits only task:featureEnablement on individual tasks. Either restore the Contact Center forwarder or remove this public enum member and its misleading “Emitted” documentation.
AGENTS.md reference: packages/@webex/contact-center/AGENTS.md:L46-L50
Useful? React with 👍 / 👎.
| const consultFeatures = summaryFeatureMap.get(consultInteractionId) || {}; | ||
| if (!consultFeatures.midCallEnabled) { |
There was a problem hiding this comment.
Check organization flags before enabling summary UI
When an interaction reports midCallEnabled: true but the organization has consultTransferSummariesEnabled disabled or absent, this condition still opens the summary UI and invokes requestMidCallSummary(). The SDK then rejects the request as disabled, after which the sample records it as unavailable and may send a NOT_RECEIVED response even though the administrator disabled the feature; the post-call check in onWrapupEntry() has the same problem. Combine the task flag with the corresponding agentConfig.aiFeature.generatedSummaries flag before starting either flow.
Useful? React with 👍 / 👎.
Render mid-call and post-call summaries from the payload's `sections` map, falling back to `summaryText`, instead of parsing `editAdaptiveCard`: - drop extractEditFields()/isUnresolvedTemplate(); the card walker's helper had been deleted in e4145b4 while two call sites survived, so rendering threw "isUnresolvedTemplate is not defined" and surfaced as "Summary unavailable" on every summary path - section keys are already the contract for edited summaries (`summary: Sections | string`), so the edit delta no longer depends on the card's Input.Text ids matching the section names - pin display order via SUMMARY_SECTION_ORDER; payload key order is not guaranteed and unknown keys render last Also dismiss summaries once wrapup completes. COMPLETED is a final state emitting only task:wrappedup, so task:end -- where dismissAllSummaryUI() was wired -- never fires when wrapUpRequired is true, leaving the panels on screen and the summary in sessionStorage. The task:wrappedup handler now runs the same teardown, which also covers auto-wrapup. It waits on the in-flight wrapupCall() first: that reads the edited fields from the DOM and the flags from summaryFeatureMap only after wrapup() resolves, so tearing down synchronously would drop the agent's edits from the response. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
left a comment
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1bf36529bf
ℹ️ 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".
| } | ||
| }); | ||
|
|
||
| task.on('task:postCallSummary', (payload) => { |
There was a problem hiding this comment.
Persist post-call results from the promise handler
This listener never runs because the SDK returns initiating-agent post-call summaries exclusively through requestPostCallSummary() and does not define or emit task:postCallSummary. Consequently the later saveSummaryState() call never stores a summary after it arrives—the feature-enablement handler generally saved only the earlier empty state—so a hydrate or page reload during wrap-up cannot restore the generated summary or its counters. Move the persistence work into the request Promise's success handler.
Useful? React with 👍 / 👎.
…i-docs Delete the scratch documents produced during the artifiser run: requirement.md, ai-summary.md, ai-summary-requirements.md, ai-summary-open-issues.md, the three ai-summary-*-flow.md pages, and design/default/ (design_spec.md and implementation_dag.json). Four in-package ai-docs referenced those files in 11 places, several calling ai-summary.md "the canonical contract", so each link is replaced by the information it carried rather than dropped: - metrics/ai-docs/AGENTS.md now tabulates the six AI summary metrics with owner and success condition, the eight terminal inbound-drop paths, and the explicit privacy allow/deny lists. - metrics/ai-docs/ARCHITECTURE.md names metrics/constants.ts as the source of truth for the literals and spells out the allowed/forbidden field sets. - services/task/ai-docs/AGENTS.md points at types.ts, constants.ts and config/types.ts for public signatures instead of the deleted contract. - services/task/ai-docs/ARCHITECTURE.md gains an "AI Summary Flows" section carrying the post-call and mid-call-initiator sequence diagrams, both IGNORED branch rules, the receiver component diagram and delivery sequence, and the task:midCallSummaryForReceivingAgent usage snippet. Every new relative path resolves to a real file and both new anchors match real headings. Also guard the receiving-agent summary in the sample app: a mid-call summary payload with no non-empty sections and no summaryText is now ignored instead of buffered, and the incoming panel stays hidden rather than showing a placeholder. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
left a comment
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 05120c1eb9
ℹ️ 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".
| numberOfTimesEdited: 0, | ||
| numberOfTimesCopied: 0, | ||
| feedback: 'none', | ||
| state: 'IGNORED', |
There was a problem hiding this comment.
Wait for pending summaries before reporting them ignored
When the agent clicks Initiate Consult while requestMidCallSummary() is still pending, midCallSummary.payload and requestFailed are both false, so this branch sends IGNORED and proceeds with the handoff. The request can then resolve after the handoff has started, too late to include the generated summary; the transfer flow has the same race. Track and await the in-flight mid-call request, or disable initiation until it settles, before selecting the response state.
Useful? React with 👍 / 👎.
|
|
||
| task.updateTaskData(updateTaskData); | ||
| this.taskCollection[taskData.interactionId] = task; | ||
| this.retainFeatureEnablementForTask(task); |
There was a problem hiding this comment.
Replay flags after campaign reservation re-keying
When a FEATURE_ENABLEMENT frame for the assigned interaction ID arrives while a campaign-preview task is still stored under its reservation ID, it is retained as an orphan. The assignment path then re-keys the task and this call cancels the orphan timeout, but unlike creation paths it never emits task:featureEnablement; consumers that attached listeners when the reservation task was surfaced therefore never receive the flags and cannot enable summary handling. Ensure the re-key/update path replays the retained payload after the task event is published.
Useful? React with 👍 / 👎.
# Conflicts: # docs/samples/contact-center/app.js # packages/@webex/contact-center/src/cc.ts # packages/@webex/contact-center/src/constants.ts # packages/@webex/contact-center/src/services/task/Task.ts # packages/@webex/contact-center/src/services/task/TaskFactory.ts # packages/@webex/contact-center/src/services/task/TaskManager.ts # packages/@webex/contact-center/src/services/task/ai-docs/ARCHITECTURE.md # packages/@webex/contact-center/src/services/task/types.ts # packages/@webex/contact-center/test/unit/spec/cc.ts # packages/@webex/contact-center/test/unit/spec/services/task/voice/Voice.ts
left a comment
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d556e9f33f
ℹ️ 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.metricsManager.trackEvent( | ||
| metricName, | ||
| { | ||
| taskId: this.data?.interactionId, | ||
| duration_ms: Math.max(0, Date.now() - operationStartedAt), | ||
| ...fields, | ||
| } as never, | ||
| ['operational'] | ||
| ); |
There was a problem hiding this comment.
Isolate summary operation metrics from product results
Guard this tracking call so telemetry failures cannot change the result of a completed summary operation. Each request/response method invokes this helper inside its product try block, so if MetricsManager.trackEvent() throws after a summary is received or a response is accepted, control enters the failure path and the public API rejects; response callers may then retry an event the backend already processed. Metrics must remain non-blocking.
AGENTS.md reference: packages/@webex/contact-center/AGENTS.md:L44-L50
Useful? React with 👍 / 👎.
| this.trackFeatureEnablementReceived({ | ||
| validationOutcome, | ||
| postCallEnabled: | ||
| featurePayload.postCallEnabled === undefined ? 'absent' : featurePayload.postCallEnabled, | ||
| midCallEnabled: | ||
| featurePayload.midCallEnabled === undefined ? 'absent' : featurePayload.midCallEnabled, | ||
| }); | ||
| this.aiSummaryCoordinator.setFeatureEnablement(featurePayload, matchingTask !== undefined); |
There was a problem hiding this comment.
Store feature flags before recording telemetry
Move or isolate this metric so a telemetry exception cannot abort feature processing. In the inspected FEATURE_ENABLEMENT path, this call runs before setFeatureEnablement() and task emission; the outer realtime dispatcher catches the exception and returns, leaving a valid interaction without flags, which makes both summary request APIs reject as disabled. The added unit test that makes this tracker throw confirms this exact dispatch path currently stops here.
AGENTS.md reference: packages/@webex/contact-center/AGENTS.md:L44-L50
Useful? React with 👍 / 👎.
left a comment
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: adc46edbbf
ℹ️ 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.aiSummaryCoordinator.clearAISummaryState(); | ||
| } | ||
|
|
||
| private configureTaskAISummary(task: ITask): void { |
There was a problem hiding this comment.
Configure tasks recovered after owner promotion
Invoke this configuration path for tasks created by handleContactOwnerChanged() as well. When an owner-promotion event reconstructs a missing task, that handler creates and registers it without calling configureTaskAISummary() or retaining/delivering its feature snapshot, unlike every other factory path; consequently requestPostCallSummary() and requestMidCallSummary() on the recovered task always reject with AI_SUMMARY_NOT_INITIALIZED, even when summaries are enabled.
Useful? React with 👍 / 👎.
left a comment
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d2e1f69549
ℹ️ 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".
| summaryReceived: true, | ||
| summary: buildSummaryPayload('consult-summary'), | ||
| numberOfTimesViewed: midCallSummary.numberOfTimesViewed, | ||
| numberOfTimesEdited: midCallSummary.numberOfTimesEdited, |
There was a problem hiding this comment.
Record edits before cancellation responses
When an agent edits a generated consult summary and then cancels the dialog, this branch sends the edited output from buildSummaryPayload() but leaves numberOfTimesEdited at zero because it never performs the isSummaryEdited() check used by the initiation path. The transfer-cancellation branch has the same behavior, so both flows report inaccurate interaction counters; detect the edit and increment the counter before constructing either cancellation response.
Useful? React with 👍 / 👎.
left a comment
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eb933b62aa
ℹ️ 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".
| ): boolean => | ||
| knownSectionKeys.every((key) => payload[key] === undefined || typeof payload[key] === 'string'); |
There was a problem hiding this comment.
Validate every extension section value
When an initiator frame contains an extension section such as sections: {futureSection: {invalid: true}}, this helper validates only the known keys and accepts the payload. The request then resolves as PostCallSummaryEventPayload or MidCallSummaryEventPayload, whose section values are declared as strings, so JavaScript consumers that trust the public contract can fail when formatting the unexpected object. Preserve support for future section names, but require every present section value to be a string.
Useful? React with 👍 / 👎.
| midCallEnabled: !!payload.midCallEnabled, | ||
| postCallEnabled: !!payload.postCallEnabled, | ||
| }); | ||
| saveSummaryState(payload.interactionId); |
There was a problem hiding this comment.
Scope persisted summary state to the event's task
When multiple tasks coexist, a feature-enablement event for task B calls saveSummaryState(B), but that function serializes the single global postCallSummary, which may still contain task A's generated or edited summary. This stores A's content under B's interaction ID, and a later hydrate or reload of B can restore and display the wrong contact's summary. Persist only B's task-scoped flags here, or maintain summary state per interaction instead of copying the global summary.
Useful? React with 👍 / 👎.
left a comment
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 02de25bc4a
ℹ️ 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".
| export const CC_AI_SUMMARY_EVENTS = { | ||
| POST_CALL_SUMMARY: 'POST_CALL_SUMMARY', | ||
| MID_CALL_SUMMARY: 'MID_CALL_SUMMARY', |
There was a problem hiding this comment.
Preserve the legacy summary members on CC_TASK_EVENTS
When an existing consumer upgrades while referencing the publicly exported CC_TASK_EVENTS.MID_CALL_SUMMARY or .POST_CALL_SUMMARY, both properties now become undefined at runtime (and disappear from its TypeScript surface) because they were moved exclusively to the new CC_AI_SUMMARY_EVENTS object. Keep aliases on CC_TASK_EVENTS for compatibility or provide an explicit migration plan rather than breaking the existing package API.
AGENTS.md reference: packages/@webex/contact-center/AGENTS.md:L83-L85
Useful? React with 👍 / 👎.
|
|
||
| // Clean up task creation time tracking | ||
| taskCreationTimes.delete(task.data.interactionId); | ||
| summaryFeatureMap.delete(task.data.interactionId); |
There was a problem hiding this comment.
The termination cleanup removes the in-memory feature flags but leaves this interaction's persisted post-call summary in sessionStorage. If a task ends before wrapupCall() (for example, a non-wrapup termination), the generated summary remains available for the rest of the browser session and the storage map grows indefinitely. Call clearSummaryStorageState(task.data.interactionId) here alongside the other task-end cleanup.
| * @enum {string} | ||
| * @public | ||
| */ | ||
| export const CC_AI_SUMMARY_EVENTS = { |
There was a problem hiding this comment.
[P1] Preserve the legacy CC_TASK_EVENTS.MID_CALL_SUMMARY and .POST_CALL_SUMMARY members (for example as aliases). Moving them exclusively to CC_AI_SUMMARY_EVENTS makes existing SDK consumers receive undefined at runtime after upgrade, which is a breaking public-API change.
| return correlation?.interactionId === featurePayload.interactionId; | ||
| }); | ||
|
|
||
| this.trackFeatureEnablementReceived({ |
There was a problem hiding this comment.
[P2] Keep telemetry non-blocking here. If trackFeatureEnablementReceived() throws, this valid frame is never retained or emitted, so the summary APIs later reject as disabled. Store/deliver the flags first, or isolate metrics failures.
|
|
||
| this.postCallSummaryResponseContext = {conversationId, interactionId}; | ||
|
|
||
| this.trackAISummaryOperation( |
There was a problem hiding this comment.
[P2] Isolate this metric from the product operation. A MetricsManager.trackEvent() failure after a summary has already resolved sends control to the catch block and rejects the public API; response callers may then retry an event the backend already accepted.
| } | ||
| } | ||
|
|
||
| private handleReceivingAgentSummaryEvent(payload: Record<string, unknown>): void { |
There was a problem hiding this comment.
[P2] Validate the complete receiving-summary payload before casting and emitting it. With only these two checks, {conversationId: 'c', summaryText: {invalid: true}} is delivered as MidCallSummaryReceivingAgentPayload even though consumers are promised a string summary.
| this.configureTaskAISummary(task); | ||
| this.setupTaskListeners(task); | ||
| this.taskCollection[payload.interactionId] = task; | ||
| this.retainFeatureEnablementForTask(task); |
There was a problem hiding this comment.
[P2] This replays retained feature flags before the lifecycle pipeline publishes the reserved task to consumers. A host therefore cannot yet attach task:featureEnablement, and the only notification is lost. Replay after the task has been surfaced.
|
|
||
| // Clean up task creation time tracking | ||
| taskCreationTimes.delete(task.data.interactionId); | ||
| summaryFeatureMap.delete(task.data.interactionId); |
There was a problem hiding this comment.
[P2] Also clear sessionStorage here. A task that terminates outside wrapupCall() leaves its generated post-call summary persisted for the rest of the session, which retains stale contact content and grows the storage map.
| if (midCallSummary.payload) { | ||
| await currentTask.sendMidCallSummaryResponse({ | ||
| summaryReceived: true, | ||
| summary: buildSummaryPayload('consult-summary'), |
There was a problem hiding this comment.
[P2] Capture the task that opened this flow instead of using mutable currentTask when the dialog closes. If another task is assigned while a summary is pending, this response can be sent with the second task's interaction/conversation identifiers.
COMPLETES WXCC-9127
This pull request addresses
WxCC generates AI call summaries — a mid-call summary the agent reviews before a consult or
transfer, and a post-call summary the agent reviews during wrapup — but the JS SDK had no
surface for them. Custom desktops built on this SDK could not request a summary, show it to the
agent, capture the agent's edits and feedback, or hand a summary to the receiving agent on a
transfer.
The delivery model makes this awkward for consumers to do themselves. Summaries are requested over
one channel and delivered asynchronously over Contact Center realtime as a separate inbound frame,
so a consumer would have to correlate request to response by
conversationId, impose its owntimeout, and cope with frames that arrive before the task they belong to is registered (both the
receiving agent's summary and the per-interaction feature flags can land early). Each consumer
re-implementing that correlation is where the bugs live.
by making the following changes
Task API — four methods on
ITask, each returning a promise that settles on the matchinginbound frame:
requestPostCallSummary()PostCallSummaryEventPayloadsendPostCallSummaryResponse(payload)requestMidCallSummary(actionType)'CONSULT' | 'TRANSFER'; resolves withMidCallSummaryEventPayloadsendMidCallSummaryResponse(payload, actionType)Two new task events, so consumers do not maintain their own
interactionId → statemaps:task:midCallSummaryForReceivingAgent— the summary that travelled with a transfer, replayed onthe receiving agent's task even when the frame arrived before that task existed.
task:featureEnablement— per-interactionmidCallEnabled/postCallEnabledflags used to gatethe summary UI. Fires at registration time if the frame arrived first.
AISummaryCoordinator(new) owns the request/response correlation the consumer would otherwisewrite: pending-request maps keyed by conversation, a 30s timeout per request
(
AI_SUMMARY_REQUEST_TIMEOUT_MS), buffering of early receiver summaries and orphan feature-flagframes with matching retention windows, cancellation on task teardown, and rejection of a duplicate
in-flight request with
AI_SUMMARY_REQUEST_ALREADY_PENDING.Transport —
ApiAiAssistant.sendSummaryGetEvent()/sendSummaryResponseEvent(), with routingfor the new inbound frames through
CC_AI_SUMMARY_EVENTS.Failure modes are typed, not thrown strings —
AI_SUMMARY_ERROR_CODEScoversPOST_CALL_SUMMARY_DISABLED,MID_CALL_SUMMARY_DISABLED,POST_CALL_SUMMARY_TIMEOUT,MID_CALL_SUMMARY_TIMEOUT,AI_ASSISTANT_BASE_URL_NOT_AVAILABLEandAI_SUMMARY_REQUEST_ALREADY_PENDING, so a consumer can distinguish "feature off" from "timed out"without string matching.
Behavioral metrics for each get/response success and failure, feature-enablement receipt, and
inbound frames dropped with no matching task.
Public types exported from the package entry point:
PostCallSummaryEventPayload,MidCallSummaryEventPayload,MidCallSummaryReceivingAgentPayload,FeatureEnablementEventPayload,PostCallSummarySections,MidCallSummarySections, the response payload types,SummaryCounters,AISummaryActionType,AISummaryFeedback, and the summary state unions — plusCC_AI_SUMMARY_EVENTS,AI_SUMMARY_ERROR_CODESandAIAssistantEventName.Sample app (
docs/samples/contact-center/) exercises the whole surface end to end: summarypanels for consult, transfer, incoming-transfer and wrapup; read-only and edit modes rendered from
the payload's
sectionsmap with asummaryTextfallback; a delta payload so only edited sectionsare sent; thumbs up/down feedback and view/edit/copy counters; suggested wrapup codes applied to the
dropdown; and
sessionStoragepersistence so a refresh mid-wrapup does not lose the summary.Also in this branch: minified sample bundles (
docs/samples/*.min.js) are removed from git trackingand ignored, and the
ai-docsundercontact-center/srcare updated to match the new flows.https://app.vidcast.io/share/c826de62-f149-49ac-83f1-8cfa32a9ffc3
Change Type
The following scenarios were tested
Automated —
yarn jestinpackages/@webex/contact-center: 34 suites, 1088 tests, allpassing. Unit tests added or extended for every new unit:
AISummaryCoordinator,Task,TaskManager,TaskUtils,ApiAiAssistant,cc, packageindex,config,core/Utilsandtask/voice/Voice. Coverage includes:sendPostCallSummaryResponsewith edits, counters and wrapup codeCONSULTandTRANSFER, and the response for eachfeature-enablement retention), and the buffer expiring
AI_SUMMARY_REQUEST_ALREADY_PENDINGManual, against a live org (walkthrough linked above):
midCallEnabled/postCallEnabledare offNOT_RECEIVEDstate sent; summary ignored —IGNOREDstate sentsessionStorageThe 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 - Please Specify
Claude Code
This PR is related to
I certified that
Make sure to have followed the contributing guidelines before submitting.