Skip to content

feat[contact-center]: Mid call and Post Call summaries - #5171

Open
rsarika wants to merge 55 commits into
webex:nextfrom
rsarika:cc-summaries
Open

feat[contact-center]: Mid call and Post Call summaries #5171
rsarika wants to merge 55 commits into
webex:nextfrom
rsarika:cc-summaries

Conversation

@rsarika

@rsarika rsarika commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

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 own
timeout, 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 matching
inbound frame:

Method Purpose
requestPostCallSummary() Resolves with PostCallSummaryEventPayload
sendPostCallSummaryResponse(payload) Sends the agent's edits, counters, feedback and wrapup code
requestMidCallSummary(actionType) 'CONSULT' | 'TRANSFER'; resolves with MidCallSummaryEventPayload
sendMidCallSummaryResponse(payload, actionType) Sends the agent's edits, counters and feedback

Two new task events, so consumers do not maintain their own interactionId → state maps:

  • task:midCallSummaryForReceivingAgent — the summary that travelled with a transfer, replayed on
    the receiving agent's task even when the frame arrived before that task existed.
  • task:featureEnablement — per-interaction midCallEnabled / postCallEnabled flags used to gate
    the summary UI. Fires at registration time if the frame arrived first.

AISummaryCoordinator (new) owns the request/response correlation the consumer would otherwise
write: pending-request maps keyed by conversation, a 30s timeout per request
(AI_SUMMARY_REQUEST_TIMEOUT_MS), buffering of early receiver summaries and orphan feature-flag
frames with matching retention windows, cancellation on task teardown, and rejection of a duplicate
in-flight request with AI_SUMMARY_REQUEST_ALREADY_PENDING.

TransportApiAiAssistant.sendSummaryGetEvent() / sendSummaryResponseEvent(), with routing
for the new inbound frames through CC_AI_SUMMARY_EVENTS.

Failure modes are typed, not thrown stringsAI_SUMMARY_ERROR_CODES covers
POST_CALL_SUMMARY_DISABLED, MID_CALL_SUMMARY_DISABLED, POST_CALL_SUMMARY_TIMEOUT,
MID_CALL_SUMMARY_TIMEOUT, AI_ASSISTANT_BASE_URL_NOT_AVAILABLE and
AI_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 — plus
CC_AI_SUMMARY_EVENTS, AI_SUMMARY_ERROR_CODES and AIAssistantEventName.

Sample app (docs/samples/contact-center/) exercises the whole surface end to end: summary
panels for consult, transfer, incoming-transfer and wrapup; read-only and edit modes rendered from
the payload's sections map with a summaryText fallback; a delta payload so only edited sections
are sent; thumbs up/down feedback and view/edit/copy counters; suggested wrapup codes applied to the
dropdown; and sessionStorage persistence 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 tracking
and ignored, and the ai-docs under contact-center/src are updated to match the new flows.

https://app.vidcast.io/share/c826de62-f149-49ac-83f1-8cfa32a9ffc3

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

Automatedyarn jest in packages/@webex/contact-center: 34 suites, 1088 tests, all
passing.
Unit tests added or extended for every new unit:
AISummaryCoordinator, Task, TaskManager, TaskUtils, ApiAiAssistant, cc, package index,
config, core/Utils and task/voice/Voice. Coverage includes:

  • post-call request → resolve → sendPostCallSummaryResponse with edits, counters and wrapup code
  • mid-call request for both CONSULT and TRANSFER, and the response for each
  • summary frame arriving before the task is registered (receiver buffer and orphan
    feature-enablement retention), and the buffer expiring
  • request timeout at 30s for both summary types, and cancellation on task teardown
  • duplicate in-flight request rejected with AI_SUMMARY_REQUEST_ALREADY_PENDING
  • feature-disabled and missing-base-URL rejections
  • inbound frames with no matching task counted as dropped
  • metrics emitted on each success and failure path

Manual, against a live org (walkthrough linked above):

  • consult and transfer from the initiating agent — summary requested, reviewed, edited, sent
  • receiving agent sees the transferred summary on task assignment
  • post-call summary during wrapup — reviewed, edited, feedback given, submitted with the wrapup code
  • summary panels gated correctly when midCallEnabled / postCallEnabled are off
  • agent wraps up before the summary arrives — response still sent once it resolves
  • summary never arrives — NOT_RECEIVED state sent; summary ignored — IGNORED state sent
  • refresh mid-wrapup restores the pending post-call summary from sessionStorage

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 - Please Specify

      Claude Code

  • This PR is related to

    • Feature
    • Defect fix
    • Tech Debt
    • Automation

I certified that

  • I have read and followed contributing guidelines
  • I discussed changes with code owners prior to submitting this pull request
  • I have not skipped any automated checks
  • All existing and new tests passed
  • I have updated the documentation accordingly

Make sure to have followed the contributing guidelines before submitting.

rsarika added 30 commits August 7, 2026 11:31
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.
docs/samples/{calling,meetings,webex}.min.js and their .map files are
build outputs regenerated by `npm test`. While tracked, every build run
inflates `git diff HEAD` by ~88 MB, exceeding the Artificer 16 MiB
implementation-evidence limit. Remove from the index and add missing
entries to .gitignore so future builds leave no git footprint.
@rsarika
rsarika requested a review from a team as a code owner August 14, 2026 03:27

@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: 1e394eb37a

ℹ️ 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 type TaskResponse = AgentContact | Error | void;

export type AISummaryActionType = 'CONSULT' | 'TRANSFER';

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 Document the exported AI-summary types as public

Add JSDoc containing @public to this alias and the other newly exported AI-summary types in this block. They are re-exported from src/index.ts as part of the package API, but currently lack the package's required public-type documentation, leaving the new consumer-facing surface undocumented.

AGENTS.md reference: packages/@webex/contact-center/AGENTS.md:L358-L366

Useful? React with 👍 / 👎.

const createTask = (interactionId: string) =>
({
data: {interactionId},
emit: jest.fn(),

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 Use the mandated Sinon and Chai test stack

Replace the Jest mocks, expectations, and fake timers introduced throughout the new AI-summary suites with Sinon and assert from @webex/test-helper-chai. Keeping these tests on a second mocking/assertion stack violates the repository's explicit unit-test conventions and makes the new suite inconsistent with the required helpers and timer controls.

AGENTS.md reference: AGENTS.md:L43-L48

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: 8e1158c973

ℹ️ 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.agentId
);

this.configureTaskAISummary(task);

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 Pass the agent name into reserved tasks

When the normal AGENT_CONTACT_RESERVED path creates a task, the preceding factory call passes only agentId, even though the new constructor parameter carries agentName. Consequently these tasks retain agentName === undefined; every sendMidCallSummaryResponse() then serializes agentName: '', and the transport validation currently allows that invalid response to reach the backend. Pass this.agentName at this creation site, as the other new task-creation paths do.

Useful? React with 👍 / 👎.

if (midCallSummary.payload) {
const consultEdited = isSummaryEdited('consult-summary', midCallSummary.payload);
if (consultEdited) midCallSummary.numberOfTimesEdited += 1;
const consultSummaryPayload = consultEdited ? buildSummaryPayload('consult-summary') : {};

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 Preserve unedited summaries in response payloads

When an agent accepts a generated summary without editing it, this branch substitutes {} instead of the rendered/generated summary, while still reporting summaryReceived: true. The same conditional appears in the transfer and post-call branches, so the common unedited path discards the summary content before it is sent to the backend and, for handoffs, leaves the receiving agent without the generated text. Build the response summary from the displayed fields for both edited and unedited cases.

Useful? React with 👍 / 👎.


task.on('task:midCallSummaryForReceivingAgent', (payload) => {
console.info('[Receiving agent] mid-call summary buffered, waiting for task:assigned', payload);
incomingMidCallSummaryPayload = payload;

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 Render receiver summaries that arrive after assignment

If task:midCallSummaryForReceivingAgent fires after the matching task has already emitted task:assigned, this handler only stores the payload in a global variable; the only rendering code is inside the assignment listener, which will not run again. The summary therefore remains hidden and can even be rendered for the next unrelated task that becomes assigned. Render immediately for an already-assigned task or retain the payload per task/conversation rather than in one global slot.

Useful? React with 👍 / 👎.

…ove agentName from response API

- app.js: send IGNORED (summaryReceived:false, zero counters) in initiateConsult,
  initiateTransfer, and wrapupCall when feature is enabled but no summary was triggered
- Task.ts: add IGNORED to MID_CALL_SUMMARY_UNAVAILABLE_STATES to accept it on the
  summaryReceived:false branch
- types.ts: extend MidCallUnavailableResponse.state to include IGNORED
- Spec docs: document IGNORED branch in ai-summary.md, initiator-flow, postcall-flow;
  update agentName to reflect SDK-sourced (not caller-provided) contract
- ai-docs: update task AGENTS.md and ARCHITECTURE.md to reflect IGNORED on the
  unavailable branch and the MidCallUnavailableResponse type change
- Open issues: remove resolved issues 6 and 8
- Tests: fix DummyTask constructor to supply agentName; remove agentName from
  createMidCallResponsePayload factory; fix rejection test (summaryReceived:false+IGNORED
  is now valid); add acceptance test for that branch; add setAgentName to cc mocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@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: 7227a63f12

ℹ️ 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 +641 to +643
await currentTask.sendMidCallSummaryResponse({
summaryReceived: true,
summary: buildSummaryPayload('consult-summary'),

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 Bind summary responses to the initiating task

Capture the task that opened the consult dialog and send the cancellation response through that task rather than the mutable global currentTask. If another task emits task:assigned while this dialog is awaiting a summary, its handler automatically selects the new task; closing the original dialog then sends the first interaction's summary through the newly selected task, causing the SDK to derive the wrong interaction and conversation identifiers and potentially disclose summary content across interactions.

Useful? React with 👍 / 👎.

…p codes, session persistence

Issue 12: renderSummarySection now renders in read-only mode (labeled text) with an
Edit button; clicking Edit switches to textarea inputs (renderSummaryEditMode).
summaryOriginalPayload map stores original payload per prefix.

Issue 13: buildSummaryPayload now sends only sections that differ from the original
(delta). Unchanged sections are omitted; unedited payloads remain {}.

Issue 14: applySuggestedWrapUpCodes pre-selects the first matching wrapup code in the
dropdown when post-call summary includes a suggestedWrapUpCodes array.

Issue 15: saveSummaryState/restoreSummaryState/clearSummaryStorageState persist post-call
summary payload and feature flags to sessionStorage keyed by interactionId. Restored in
handleTaskHydrate after page refresh; cleared on successful wrapup.

Closes Issues 12, 13, 14, 15 in ai-summary-open-issues.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@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: ae51c95c1f

ℹ️ 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".

console.info('📝 [task:wrapup] Delayed UI update for wrapup controls');
updateCallControlUI(currentTask);
}, 0);
onWrapupEntry(currentTask);

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 Deduplicate post-call requests on wrap-up

Guard this call so the sample starts only one post-call request per task. Several existing state-machine transitions, such as CONNECTED handling CONTACT_ENDED, execute emitTaskWrapup while entering WRAPPING_UP, whose entry action emits the same event again. Consequently this listener invokes onWrapupEntry() twice, resets the shared summary state, and replaces postCallSummaryPending with a second request that rejects as already pending; if the agent wraps up quickly, wrapupCall() can await that rejected request instead of the real in-flight request and send an incorrect unavailable response.

Useful? React with 👍 / 👎.

for (const code of suggestedCodes) {
for (let i = 0; i < wrapupCodesDropdownElm.options.length; i++) {
const opt = wrapupCodesDropdownElm.options[i];
if (opt.value === code || opt.text === code) {

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 Match suggested wrap-up codes by name

Read the suggested code's name when comparing it with dropdown options. The new inbound contract and validator define suggestedWrapUpCodes as objects such as {name: string}, so comparing opt.value or opt.text directly with code always compares a string with an object. As a result, valid backend suggestions never select a wrap-up code in the sample.

Useful? React with 👍 / 👎.

Consumers no longer need to listen to cc:featureEnablement and maintain
an interactionId → flags map manually. The SDK now emits the new
task:featureEnablement event directly on the task object, covering both
cases: frame arrives while task is registered (immediate delivery via
handleFeatureEnablementEvent) and frame arrives before task creation
(orphan path delivers at registration via deliverFeatureEnablementToTask).

- types.ts: add TASK_FEATURE_ENABLEMENT = 'task:featureEnablement' to TASK_EVENTS
- TaskManager: emit on matching task in handleFeatureEnablementEvent;
  extract deliverFeatureEnablementToTask (called only from creation paths)
  so consumers receive exactly one emission per enablement frame
- app.js: remove cc:featureEnablement listener; wire task:featureEnablement
  inside wireSummaryListeners with sessionStorage persistence
- ai-docs/ARCHITECTURE.md: document single-emission guarantee, orphan
  window boundary, and agentName param in TaskFactory.createTask diagram
- ai-summary-open-issues.md: add Issue 17 as wrong implementation — fixed
- tests: new TaskManager tests for live-delivery and orphan-path delivery;
  fix campaign test agentName arg; remove agentName from index.ts fixtures

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@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

return new Digital(contact, data, wrapupData, agentId);

P2 Badge Forward the agent name through digital task construction

For chat, email, and social tasks, the factory accepts agentName but discards it here, and Digital consequently never forwards a name to the base Task. These tasks inherit the new mid-call summary APIs without a media-channel gate, so an enabled digital task can successfully request a summary but sendMidCallSummaryResponse() serializes agentName: '', producing an invalid handoff response. Pass the name through the digital constructor as is done for voice tasks.

ℹ️ 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.setupTaskListeners(task);
this.taskCollection[payload.interactionId] = task;
this.retainFeatureEnablementForTask(task);
this.deliverFeatureEnablementToTask(task);

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 Emit retained feature flags after publishing the task

When a FEATURE_ENABLEMENT frame arrives before AGENT_CONTACT_RESERVED, this call replays the retained payload before the lifecycle pipeline sends the state-machine event that emits task:incoming. Because consumers do not receive the task object until that later event, they cannot yet attach a task:featureEnablement listener and the only task-level notification is lost. Replay the payload after the task has been surfaced, as is already done for buffered receiving summaries.

AGENTS.md reference: packages/@webex/contact-center/src/services/task/ai-docs/AGENTS.md:L114-L117

Useful? React with 👍 / 👎.

rsarika and others added 2 commits August 18, 2026 00:13
Remove adaptive card parsing paths. renderSummaryText now checks
payload.sections first (map of section-name → string, formatted with
auto-generated labels), then falls back to payload.summaryText.
Removes the now-unused extractInputTextValues and extractTextBlockValues
helpers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After removing agentName from the public caller-facing payload types
(MidCallReceivedResponse / MidCallUnavailableResponse), the transport
union type lost the field. The SDK still injects agentName from agent
registration into the mid-call transport payload — add it to the
transport-layer type so ApiAiAssistant.ts compiles cleanly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@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: 544af1f176

ℹ️ 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".

wrapupData?: WrapupData,
agentId?: string
agentId?: string,
agentName?: string

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 Forward agent names into digital tasks

Beyond the reserved-task creation path already noted, the newly added agentName parameter is never forwarded by the factory's Digital branch. Consequently every CHAT, EMAIL, or SOCIAL task has this.agentName === undefined even when its TaskManager caller supplies the profile name, so a mid-call transfer response from those tasks serializes agentName: ''. Pass the name through the Digital constructor and its super(...) call as well.

Useful? React with 👍 / 👎.

}

private handleReceivingAgentSummaryEvent(payload: Record<string, unknown>): void {
if (!isNonEmptyString(payload.conversationId)) {

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 Reject malformed receiving-summary fields

When a subsequent-agent frame has a non-empty conversationId, this path accepts and emits the rest of the payload without validating the declared receiver fields. For example, {conversationId: 'c', summaryText: {invalid: true}} is delivered as MidCallSummaryReceivingAgentPayload even though summaryText must be a string; consumers that trust the public type can then fail while rendering it. Apply the same optional-field shape checks used for initiator summaries before selecting a task or buffering the payload.

Useful? React with 👍 / 👎.

rsarika and others added 3 commits August 18, 2026 00:35
# 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>

@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: 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".

Comment on lines +4020 to +4021
const wrapupInteractionId = currentTask?.data?.interactionId;
const wrapupSummaryFeatures = summaryFeatureMap.get(wrapupInteractionId) || {};

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

rsarika and others added 2 commits August 18, 2026 01:28
…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>

@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: 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".

Comment on lines +441 to +442
/** Emitted when AI summary feature enablement changes for an interaction */
FEATURE_ENABLEMENT = 'cc:featureEnablement',

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

Comment on lines +658 to +659
const consultFeatures = summaryFeatureMap.get(consultInteractionId) || {};
if (!consultFeatures.midCallEnabled) {

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

@rsarika rsarika added the validated If the pull request is validated for automation. label Aug 18, 2026
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>
@github-actions github-actions Bot removed the validated If the pull request is validated for automation. label Aug 18, 2026
@rsarika rsarika added the validated If the pull request is validated for automation. label Aug 18, 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: 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) => {

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 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>
@github-actions github-actions Bot removed the validated If the pull request is validated for automation. label Aug 18, 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: 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',

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 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);

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

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