Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ endpoint testing, logs, and troubleshooting.
| Install and run the sample locally | [Local Development](docs/LOCAL_DEVELOPMENT.md) |
| Configure the gateway and connectors | [Configuration Reference](config/README.md) |
| Configure runtime JWT validation | [gRPC JWT Authentication](docs/JWT_AUTHENTICATION.md) |
| Pass a virtual-agent summary to a human agent | [BYOVA Handoff Summary](docs/BYOVA_HANDOFF_CONTEXT.md) |
| Pass virtual-agent summary and routing context to a human agent | [BYOVA Handoff Context](docs/BYOVA_HANDOFF_CONTEXT.md) |
| Run automated and service tests | [Testing Guide](docs/TESTING.md) |
| Configure the monitoring dashboard | [Monitoring Interface](src/monitoring/README.md) |
| Add or configure connectors | [Connector Guide](src/connectors/README.md) |
Expand Down
171 changes: 134 additions & 37 deletions docs/BYOVA_HANDOFF_CONTEXT.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Passing a Virtual-Agent Handoff Summary to Webex Contact Center
# Passing Virtual-Agent Handoff Context to Webex Contact Center

This document defines a provider-neutral contract for passing a handoff summary from a
BYOVA virtual agent to Webex Contact Center (WxCC) when the call transfers to a human agent.
The goal is to let the receiving agent understand the caller's request without asking the
caller to repeat it.
This document defines a provider-neutral contract for passing an optional handoff summary and
routing hint from a BYOVA virtual agent to Webex Contact Center (WxCC) when the call transfers
to a human agent. The summary helps the receiving agent understand the caller's request without
asking the caller to repeat it. The routing hint lets the customer's flow select an approved
human queue without exposing queue identifiers to the virtual-agent provider.

The contract applies to any virtual-agent provider. Each connector remains responsible for
translating its provider's terminal response into the canonical gateway fields described
Expand All @@ -18,26 +19,26 @@ summary:
- In the Interaction Control pane after answering
- Without depending on a provider-specific Agent Desktop widget

This document covers only the handoff summary behavior verified by this implementation.
This document covers the handoff behavior verified by this implementation.

## Data Flow

```text
Virtual-agent provider
|
| provider-specific terminal event and generated summary
| provider-specific terminal event, summary, and symbolic classification
v
Provider connector
|
| canonical handoff summary
| canonical handoff data
v
BYOVA gateway
|
| final VoiceVAResponse with TRANSFER_TO_AGENT
v
WxCC Virtual Agent V2 activity
|
| output-event metadata.summary
| output-event metadata.summary and metadata.routing_hint
v
Agent-viewable flow variable
|
Expand All @@ -49,7 +50,7 @@ The provider may generate the summary itself or return structured facts from whi
connector builds a summary. The WxCC-facing response must not depend on which approach the
provider uses.

## Canonical Gateway Handoff Summary
## Canonical Gateway Handoff Data

Provider connectors should normalize terminal handoff data into one internal shape before
the gateway creates the BYOVA response:
Expand All @@ -59,16 +60,47 @@ the gateway creates the BYOVA response:
"message_type": "transfer",
"handoff": {
"summary": "Caller wants to change the delivery address. The virtual agent did not modify the order. Verify the caller and update the address.",
"language_code": "en-US"
"routing_hint": "delivery_address_specialist"
}
}
```

`handoff.summary` contains the text intended for the receiving agent. `language_code` is
optional and identifies the language used by the summary.
`handoff.summary` contains the text intended for the receiving agent. `handoff.routing_hint`
is an optional stable symbolic business classification. It must be a 1-64 character ASCII
identifier that begins with a letter and contains only letters, numbers, `_`, or `-` (for
example, `billing_specialist`). Numeric queue IDs, free-form text, empty values, and malformed
values are omitted.

Connectors should not leak their provider's raw terminal payload into the gateway contract.
They should extract only the approved fields and normalize them into this shape.
They should extract only the approved fields and normalize them into this shape. The virtual
agent sends the business classification; the customer owns the mapping from that classification
to WxCC queue IDs.

### Connector integration contract

This is a gateway contract, not a GECX feature. Any connector can extract equivalent terminal
data from its provider and attach the canonical handoff object to its `transfer` response:

```python
from src.utils.handoff import normalize_handoff

handoff = normalize_handoff(
{
"summary": provider_summary,
"routing_hint": provider_business_classification,
}
)
return self.create_response(
conversation_id=conversation_id,
message_type="transfer",
handoff=handoff,
)
```

`normalize_handoff()` is the shared gateway allowlist. It discards provider-specific fields,
invalid values, and raw queue IDs; connectors must never pass the full provider terminal
payload. GECX uses this helper for `EndSession.metadata`, but no GECX dependency exists in the
gateway contract.

## BYOVA Transfer Response

Expand All @@ -87,7 +119,8 @@ The gateway should create one final `VoiceVAResponse` containing one
"event_type": "TRANSFER_TO_AGENT",
"name": "transfer_requested",
"metadata": {
"summary": "Caller wants to change the delivery address. The virtual agent did not modify the order. Verify the caller and update the address."
"summary": "Caller wants to change the delivery address. The virtual agent did not modify the order. Verify the caller and update the address.",
"routing_hint": "delivery_address_specialist"
}
}
]
Expand All @@ -99,11 +132,13 @@ The fields serve different purposes:
| Field | Purpose | Requirement |
| --- | --- | --- |
| `output_events[].metadata.summary` | Makes the summary available to the WxCC flow as transfer metadata | Required for the validated Agent Desktop path |
| `output_events[].metadata.routing_hint` | Makes the stable routing classification available to the WxCC flow | Optional; sent only on `TRANSFER_TO_AGENT` |
| `session_summary` | Uses the dedicated BYOVA session-summary field | Recommended when a summary is available |

The summary is intentionally present in both `session_summary` and transfer metadata. The
dedicated field preserves the BYOVA semantic model, while `metadata.summary` supports the
current WxCC flow-variable and Agent Desktop path.
current WxCC flow-variable and Agent Desktop path. `routing_hint` is intentionally not copied
to `session_summary`; it appears only in the one terminal transfer event's metadata.

The relevant protocol definitions are:

Expand All @@ -119,8 +154,14 @@ In Flow Designer, the Virtual Agent V2 activity exposes transfer-event metadata
BYOVAHandoffSummary = {{BYOVA_Virtual_Agent.MetaData.summary}}
```

Map the optional routing hint to a separate String flow variable:

```text
BYOVARoutingHint = {{BYOVA_Virtual_Agent.MetaData.routing_hint}}
```

The Virtual Agent activity name is flow-specific; replace `BYOVA_Virtual_Agent` with the
actual activity name. Configure the custom variable as:
actual activity name. Configure the summary variable as:

| Setting | Value |
| --- | --- |
Expand All @@ -132,6 +173,19 @@ actual activity name. Configure the custom variable as:
These settings live in the flow's **Global flow properties**. They do not require a custom
Agent Desktop JSON layout.

Configure `BYOVARoutingHint` separately in the same location:

| Setting | Value |
| --- | --- |
| Type | String |
| Default value | Empty |
| Agent viewable | Disabled |
| Agent editable | Disabled |

`BYOVARoutingHint` is a routing-only value. Do not add it to an Agent Desktop surface or use
it as a customer-facing label. The flow owns the mapping from its symbolic value to an approved
queue.

### 1. Create the agent-viewable variable

Open **Variable definition > Configuration**, create the String variable, and leave its
Expand Down Expand Up @@ -165,7 +219,34 @@ Keep the human-routing path independent of the optional value:
- Do not invent a fallback summary. Leave the agent-viewable variable empty when no summary
was supplied.

### 3. Select the Agent Desktop surfaces
### 3. Route with an approved customer-owned queue map

On the Virtual Agent V2 **Escalated** branch, add a second **Set Variable** activity after the
summary assignment. Select `BYOVARoutingHint`, choose **Set value**, and enter the routing-hint
expression shown above. Connect its success path to a **Case** activity whose input is
`BYOVARoutingHint`.

Configure the Case branches only with classifications approved by the customer. For example:

| Case value | Flow action |
| --- | --- |
| `billing_specialist` | Queue Contact to the approved billing queue |
| `delivery_address_specialist` | Queue Contact to the approved delivery-address queue |
| Default | Queue Contact to the normal fallback human queue |

The labels above are examples, not gateway configuration. Do not ask the virtual agent to send
a WxCC queue ID and do not use a provider-supplied ID directly as a queue target. The customer
can add, remove, or remap classifications in Flow Designer without changing the provider or
gateway.

Always connect the Case activity's **Default** branch to the normal fallback human queue. This
default handles a missing, empty, malformed, or unknown hint so the human transfer still
succeeds. If a missing nested `routing_hint` key produces an **Undefined Error** in the Set
Variable activity, connect that error path to the same fallback human queue, or guard the
assignment with an equivalent condition. Do not send the contact to a Virtual Agent failure
branch only because the optional routing hint is absent.

### 4. Select the Agent Desktop surfaces

Open **Variable definition > Desktop viewability & order**. Add
`BYOVAHandoffSummary` to both **Incoming popover** and **Interaction control pane and
Expand All @@ -174,8 +255,16 @@ configuration has been validated.

![BYOVAHandoffSummary selected for the incoming popover and Interaction control pane](images/byova-handoff-flow-desktop-viewability.png)

The transfer must continue when the provider does not supply a summary; an absent summary is
not a routing failure.
The transfer must continue when the provider does not supply a summary or routing hint; absent
handoff data is not a routing failure.

### 5. Validate before publishing

Before publishing the flow, use synthetic handoff values to verify each approved Case branch,
the Default branch for an unknown hint, and the fallback path for a missing hint. Confirm that
only `BYOVAHandoffSummary` appears in the incoming popover and interaction control pane, and
that both missing-field error paths still reach a human queue. Do not add real queue IDs,
customer data, or provider diagnostics to the test values.

## Validated Agent Desktop Behavior

Expand Down Expand Up @@ -206,17 +295,21 @@ normalization and pass-through.

The production gateway implementation should:

1. Accept a normalized handoff summary from every connector that can provide one.
1. Accept normalized `summary` and `routing_hint` fields from every connector that can provide
them.
2. Create exactly one terminal `TRANSFER_TO_AGENT` output event.
3. Copy the summary into that event's `metadata.summary` field.
4. Populate `session_summary` with the same text and language when available.
5. Allowlist supported metadata fields rather than forwarding an arbitrary provider payload.
6. Enforce configured size limits and valid scalar types.
7. Never write summary content to logs, metrics, traces, or error messages.
8. Preserve transfer behavior when the summary is missing, malformed, or too large.
4. Copy the routing hint only into that event's `metadata.routing_hint` field.
5. Populate `session_summary` with the same summary text when available, never with the routing
hint.
6. Allowlist supported metadata fields rather than forwarding an arbitrary provider payload or
raw customer queue ID.
7. Enforce valid scalar types and the symbolic routing-hint format.
8. Never write handoff content to logs, metrics, traces, or error messages.
9. Preserve transfer behavior when either optional field is missing, malformed, or unknown.

The gateway should log only safe operational facts such as whether a field was present, its
character count, the selected language, and whether validation accepted or omitted it.
character count, and whether validation accepted or omitted it.

## Summary Content Guidance

Expand All @@ -237,22 +330,26 @@ text over Markdown because the Agent Desktop variable is rendered as text.

Automated coverage should verify:

- A transfer with a summary creates one transfer event containing `metadata.summary`.
- The same value appears in `session_summary`.
- A transfer without a summary still succeeds.
- A transfer with summary and routing hint creates one transfer event containing both allowlisted
metadata keys.
- The summary, but never the routing hint, appears in `session_summary`.
- A transfer without valid handoff data still succeeds.
- Non-transfer responses do not receive handoff fields.
- Oversized or invalid values are omitted or truncated according to configuration.
- Summary text does not appear in logs.
- Invalid routing hints and provider queue IDs are omitted.
- Handoff values do not appear in logs.
- Provider-specific fields do not escape the connector boundary.

End-to-end acceptance should verify:

1. The provider or test connector produces a synthetic handoff summary.
1. The provider or test connector produces synthetic summary and symbolic routing-hint values.
2. The gateway emits a final response with one `TRANSFER_TO_AGENT` event.
3. The WxCC flow assigns `MetaData.summary` to the agent-viewable variable.
4. The incoming offer shows the summary before answer.
5. The active interaction shows the full summary after answer.
6. The call routes and completes normally when the summary is absent.
3. The WxCC flow assigns `MetaData.summary` to the agent-viewable variable and
`MetaData.routing_hint` to `BYOVARoutingHint`.
4. The Case activity maps an approved hint to its approved queue and sends missing or unknown
hints to the default human queue.
5. The incoming offer shows the summary before answer.
6. The active interaction shows the full summary after answer.
7. The call routes and completes normally when the summary or routing hint is absent.

Use synthetic content for all nonproduction validation. Disable any terminal test probe after
the test and restore the environment's approved gateway release.
5 changes: 3 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ code, not a managed connector or a production-ready service.
connectors, including known sample-only placeholders.
- [Testing Guide](TESTING.md): Automated tests, HTTP smoke tests, gRPC health checks, and
end-to-end validation.
- [BYOVA Handoff Summary](BYOVA_HANDOFF_CONTEXT.md): Provider-neutral summary metadata
contract for human-agent transfer, including validated Agent Desktop behavior.
- [BYOVA Handoff Context](BYOVA_HANDOFF_CONTEXT.md): Provider-neutral summary and routing-hint
contract for human-agent transfer, including Flow Designer mapping and validated Agent Desktop
behavior.
- [Connector Guide](../src/connectors/README.md): Connector interface, available connectors,
and extension pattern.
- [Monitoring Interface](../src/monitoring/README.md): Dashboard behavior, Webex OAuth, APIs,
Expand Down
25 changes: 17 additions & 8 deletions docs/guides/byova-gecx-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ Open `http://localhost:8080` and confirm **My GECX Agent** appears in the dashbo
2. Use schema `5397013b-7920-4ffc-807c-e8a3e0a18f43`.
3. In your WxCC flow, add the Virtual Agent / BYOVA element.
4. Select agent name **My GECX Agent** (must match `agents` in config).
5. For human escalation, follow the provider-neutral [BYOVA Handoff Context guide](../BYOVA_HANDOFF_CONTEXT.md)
to map the optional summary and routing hint into Flow Designer. GECX `EndSession` metadata
is one source for those fields; the Flow Designer mapping is the same for every connector.

## Deploying to Google Cloud Run

Expand Down Expand Up @@ -357,22 +360,28 @@ Agent escalates ─► CES EndSession { metadata: {...} }
`escalat`, `human`, `live agent`, or `handoff`. Optionally include a
`reason` string.

To give the receiving agent context, also pass an optional plain-text `summary`
through the `end_session` system tool's `params` argument:
To give the receiving agent context and an optional customer-controlled routing
classification, pass `summary` and `routing_hint` through the `end_session` system tool's
`params` argument:

```text
end_session(
reason="caller requested a human agent",
session_escalated=true,
params={"summary": "Caller wants to change a delivery address; no change was made."}
params={
"summary": "Caller wants to change a delivery address; no change was made.",
"routing_hint": "delivery_address_specialist"
}
)
```

CX Agent Studio returns `params.summary` as `EndSession.metadata.summary`. The
connector normalizes that value, and the gateway copies it to the single BYOVA
`TRANSFER_TO_AGENT.metadata.summary` event and `session_summary`. If `summary`
is absent, empty, or not text, the gateway omits both summary fields and still
transfers the call normally. Other EndSession metadata is not forwarded.
CX Agent Studio returns these values as `EndSession.metadata.summary` and
`EndSession.metadata.routing_hint`. The connector normalizes only these allowlisted fields.
The gateway copies `summary` to the single BYOVA `TRANSFER_TO_AGENT.metadata.summary` event and
`session_summary`; it copies `routing_hint` only to that event's metadata. A routing hint must
be a stable symbolic business classification (for example, `delivery_address_specialist`), not
a WxCC queue ID. If either value is absent, empty, malformed, or not text, the gateway omits it
and still transfers the call normally. Other EndSession metadata is not forwarded.

### 2. Discover exactly what your agent sends

Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ A fully functional voice AI system where customers can:
- **[Local Development](LOCAL_DEVELOPMENT.md)** - Install, run, and troubleshoot the sample locally
- **[JWT Authentication](JWT_AUTHENTICATION.md)** - Configure Webex runtime token validation
- **[Testing](TESTING.md)** - Run automated, HTTP, gRPC, and end-to-end tests
- **[BYOVA Handoff Summary](BYOVA_HANDOFF_CONTEXT.md)** - Pass a provider-neutral handoff
summary to the receiving WxCC agent
- **[BYOVA Handoff Context](BYOVA_HANDOFF_CONTEXT.md)** - Pass provider-neutral summary and
routing-hint metadata to the receiving WxCC agent
- **[Setup Guide](https://developer.webex.com/webex-contact-center/docs/byova-and-aws-lex)** - Complete step-by-step setup
- **[AWS Test Deployment Considerations](AWS_TEST_DEPLOYMENT_CONSIDERATIONS.md)** - Sanitized ALB-to-EC2 test topology, Lex access, release flow, and validation boundaries
- **[GECX Setup Guide](guides/byova-gecx-setup.md)** - Google CX Agent Studio integration walkthrough
Expand Down
Loading