Skip to content

Latest commit

 

History

202 Commits

Folders and files

Repository files navigation

Webex Contact Center BYOVA Gateway

License: Cisco Sample Code

A Python gateway that connects Webex Contact Center (WxCC) to external voice virtual-agent providers through the BYOVA gRPC and WebSocket interfaces.

This repository is functional sample code for customers and partners building or evaluating a BYOVA integration. It is not a managed connector or a production-ready deployment. The customer or implementation partner owns the gateway adaptation, hosting, security, capacity, observability, and production operations.

If you are deciding whether BYOVA fits an existing voice agent, start with Evaluating BYOVA. If you have completed a proof of concept, continue with Production Readiness.

If you want to validate the Webex-facing path before choosing a voice-agent provider, use the Local Audio Connector Configuration guide. For Google CX Agent Studio, use the GECX Setup Guide.

What the Gateway Does

At runtime, WxCC opens a bidirectional gRPC stream or a call-long WebSocket to the registered gateway endpoint. The gateway validates the signed Webex token, routes the conversation to the configured connector, and translates audio and events between WxCC and the voice-agent provider. Caller ingestion, ordered connector processing, and response delivery use independent workers with bounded per-stream queues, so WxCC can continue sending caller frames while a connector is still producing output.

The sample includes:

  • A BYOVA gRPC server with ListVirtualAgents and ProcessCallerInput
  • BYOVA WebSocket /v1/va and /v1/listVirtualAgents endpoints that can run beside gRPC in the same process
  • Separate datasource-bound JWT profiles for gRPC and WebSocket with a shared JWKS cache
  • Optional independent BYODS datasource registration and pre-expiry JWS renewal; a combined deployment uses separate Service Apps and token providers
  • A configuration-driven connector router
  • Local audio, AWS Lex, and separate Google CX Agent Studio gRPC and native WebSocket provider connectors
  • Immediate 8 kHz mu-law BYOVA CHUNK output for Google CX Agent Studio, either requested directly from CES or converted once from 24 kHz Linear16, with guarded suppression of anomalously long low-energy pre-roll and one ordered FINAL per completed normal or terminal turn
  • Direct delivery of autonomous CES no-input prompts to the active WxCC stream; barge-in is disabled by default and can be enabled only for those prompts, while caller-triggered replies retain ordered gateway speech boundaries
  • Optional recognition-assisted GECX endpointing that keeps caller audio streaming, preserves local VAD as the boundary owner, and shortens only the cancellable post-pause grace when CES has recognized the current turn
  • gRPC and HTTP health checks
  • A development monitoring dashboard
  • Unit tests and local gRPC smoke-test utilities
  • A local end-to-end caller that can correlate exact gateway outcomes through a loopback-only AWS Systems Manager port-forward to a private monitoring listener

Quick Start

Recommended for first-time setup: Follow the complete BYOVA with AWS Lex guide. It covers Webex organization enablement, the voice agent, public hosting, Service App authorization, data-source registration, gateway configuration, and the Contact Center call flow. If you have not selected a provider, use the Local Audio Connector Configuration guide for a vendor-neutral end-to-end validation. For Google CX Agent Studio, use the GECX Setup Guide. The abbreviated steps below only install and run the gateway code.

Webex Prerequisites for End-to-End Testing

Before WxCC can connect to this gateway, you need:

  • A Webex Contact Center sandbox or nonproduction organization with BYOVA enabled
  • A Service App configured with the BYODS scopes, Voice Virtual Agent schema, and the data exchange domain for your gateway
  • Authorization of that Service App by an administrator in the target organization
  • A publicly reachable TLS-enabled gRPC server URL on the authorized domain
  • An ACTIVE BYOVA data-source registration whose URL exactly matches the public server URL; the gateway can create and renew this registration when datasource management is enabled
  • A Contact Center AI virtual-agent configuration and a test flow that uses the Virtual Agent V2 activity
  • A configured gateway connector: use the local audio connector for a vendor-neutral validation, or configure an external voice agent and its compatible connector

If any of these items are missing, stop here and use the full setup guide or the local audio guide, depending on the connector you are evaluating, before attempting an end-to-end call. The registered data-source URL must also exactly match jwt_validation.datasource_url in config/config.yaml.

Local Software Prerequisites

  • Python 3.8 or later
  • macOS, Linux, or Windows

Install

git clone https://github.com/webex/webex-byova-gateway-python.git
cd webex-byova-gateway-python
python -m venv venv
source venv/bin/activate
python -m pip install -r requirements.txt
python -m grpc_tools.protoc \
  -I./proto \
  --python_out=src/generated \
  --grpc_python_out=src/generated \
  proto/*.proto

On Windows, activate the virtual environment with venv\Scripts\activate.

Configure a Local-Only Run

The checked-in configuration enables gRPC JWT validation without committing a datasource URL, so a fresh checkout intentionally refuses to start until it is configured.

For a local-only test that is not connected to Webex, set the following in config/config.yaml:

authentication:
  enabled: false

jwt_validation:
  enabled: false

Never use disabled authentication for a Webex-connected or production endpoint. For an end-to-end test, configure the exact registered datasource URL and keep JWT enforcement enabled.

Configure Automatic Datasource Management

The optional datasource lifecycle uses webex-byods-sdk to discover or register this gateway before gRPC starts accepting traffic and to renew its JWS before expiry. Configure jwt_validation.datasource_url, then enable:

data_source:
  enabled: true
  auth:
    type: "oauth_refresh"
    client_id_env: "WEBEX_BYODS_CLIENT_ID"
    client_secret_env: "WEBEX_BYODS_CLIENT_SECRET"
    refresh_token_env: "WEBEX_BYODS_REFRESH_TOKEN"

Set the named environment variables from an authorized Service App with spark-admin:datasource_read and spark-admin:datasource_write. The gateway discovers an exact URL/schema/audience/subject match when no datasource ID is configured, reconciles configuration drift, and renews the token 60 minutes before expiry by default. See the Configuration Reference for all settings and the static-token development option.

Run

python main.py

Then check:

curl http://localhost:8080/api/status
python test_health.py

The gRPC server listens on localhost:50051, and the development monitoring interface listens on http://localhost:8080. Press Ctrl+C to stop the gateway gracefully.

See Local Development for dashboard authentication, public endpoint testing, logs, and troubleshooting.

Documentation

Audience or task Guide
Complete a first end-to-end AWS Lex setup (recommended) BYOVA with AWS Lex
Evaluate BYOVA for an existing voice agent Customer Evaluation
Validate BYOVA before choosing a voice-agent provider Local Audio Connector Configuration
Install and run the sample locally Local Development
Configure the gateway and connectors Configuration Reference
Configure the WebSocket listener and contract BYOVA WebSocket Transport
Configure runtime JWT validation gRPC JWT Authentication
Pass a virtual-agent summary to a human agent BYOVA Handoff Summary
Run automated and service tests Testing Guide
Configure the monitoring dashboard Monitoring Interface
Add or configure connectors Connector Guide
Configure AWS Lex AWS Lex Configuration
Configure Google CX Agent Studio GECX Setup Guide
Test GECX or AWS Lex audio without a WxCC call Voice Agent Audio Lab
Review the known-working AWS test hosting pattern AWS Test Deployment Considerations
Configure TLS and network security Security Configuration
Prepare a derivative for production Production Readiness

The documentation index provides additional component references.

Interfaces

gRPC

  • ListVirtualAgents: Returns the configured virtual agents.
  • ProcessCallerInput: Handles bidirectional caller audio, DTMF, and conversation events.
  • grpc.health.v1.Health/Check: Reports minimal service health without a JWT so a private ALB target-group probe can operate. All BYOVA RPCs remain JWT-protected.

The protocol definitions are in proto/ and originate from the Webex Voice Virtual Agent schema.

WebSocket

  • /v1/va: Long-lived JSON text socket for a full call.
  • /v1/listVirtualAgents: JSON discovery socket that returns only agents enabled for WebSocket and then waits for the peer to close, with a bounded idle timeout.
  • /health: Minimal HTTP process health for a private load-balancer probe.

Terminal transfer and session-end responses are flushed before the gateway waits for the Webex peer to close the conversation socket, with a bounded fallback timeout for abandoned connections.

The listener uses the official WebSocket datasource schema, requires SESSION_START, preserves ordered full-duplex provider output, and shares the same pluggable connector architecture as gRPC. Connector discovery and runtime selection are transport-aware: undeclared connectors default to gRPC-only, while Local Audio and GECX declare both gRPC and WebSocket support. See BYOVA WebSocket Transport. That capability describes the WxCC-facing listener. To use WebSocket on both hops, configure GECXWebSocketConnector and restrict its advertised agent to supported_transports: ["websocket"]. The Webex Service App must be authorized for the WebSocket datasource schema before that independent wss:// datasource can be registered. Users can enable gRPC, WebSocket, or both. A single-transport deployment needs only that transport's Service App, datasource, listener, and load-balancer target. A combined deployment composes both independent profiles in one process. For AWS, use one public TLS listener with a distinct HTTP/1.1 target group on private port 8765; the AWS test deployment guide covers the safe activation order.

HTTP Monitoring

  • GET /: Development monitoring dashboard
  • GET /api/status: Gateway and connector status
  • GET /api/connections: Recent connection information
  • GET /health: HTTP process health

The monitoring interface is a development and diagnostic tool. Do not expose it in production without the controls described in the production guide.

Included Connectors

  • Local Audio: Uses the included WAV files for local development and vendor-neutral end-to-end validation over gRPC or WebSocket. See Local Audio Connector Configuration.
  • AWS Lex: Separate AWSLexConnector (WxCC gRPC) and AWSLexWebSocketConnector (WxCC WebSocket) adapters share Amazon Lex V2 RecognizeUtterance, the standard AWS SDK credential chain, and audio/session handling. The WebSocket adapter uses complete WAV responses and distinct discovery IDs. See Lex configuration.
  • Google CX Agent Studio: Streams caller audio to Gemini Enterprise for Customer Experience through CES BidiRunSession. GECXConnector uses the CES gRPC client; GECXWebSocketConnector uses Google's native JSON WebSocket gateway while sharing the same audio, turn, and terminal behavior. Use distinct agent IDs when both are loaded. See the GECX Setup Guide.

Connectors implement IVendorConnector and are loaded from config/config.yaml. See the Connector Guide for the interface contract and extension pattern.

Project Structure

webex-byova-gateway-python/
├── audio/              # Local connector audio files
├── config/             # Gateway and connector configuration
├── docs/               # Evaluation, security, testing, and operations guides
├── proto/              # BYOVA and health protocol definitions
├── schemas/            # Pinned upstream WebSocket AsyncAPI contracts
├── scripts/            # Runtime release tooling
├── src/
│   ├── auth/           # Datasource-bound JWT validation and shared JWKS cache
│   ├── connectors/     # Virtual-agent connectors
│   ├── core/           # Datasource lifecycle, gateway server, routing, and health
│   ├── generated/      # Locally generated gRPC modules
│   ├── monitoring/     # Development monitoring interface
│   ├── runtime/        # Container bootstrap and health-check helpers
│   ├── transports/     # WebSocket models, adapter, and listener
│   └── utils/          # Audio utilities
├── tests/              # Automated test suite
├── tools/              # Local development and end-to-end test tools
├── main.py             # Application entry point
├── requirements.txt    # Gateway runtime dependencies
└── requirements-dev.txt # Local tools and gateway dependencies

Build a Runtime Release Artifact

Build EC2 and server releases with the allowlisted runtime artifact builder:

scripts/build-runtime-release.sh \
  --ref HEAD \
  --output /tmp/byova-gateway-runtime.tar.gz

The archive contains only the Python gateway runtime: main.py, Python dependency metadata, audio/, config/, proto/, and src/. It deliberately excludes tools/, tests/, docs/, requirements-dev.txt, JavaScript package manifests and lockfiles, and macOS AppleDouble files.

The builder regenerates every Python gRPC module from the selected ref's proto/*.proto files and includes those modules under src/generated/. Run it from an environment where requirements.txt is installed so grpcio-tools is available; an archive missing any required generated module fails validation before it can be deployed.

tools/byova_e2e/, tools/voice_agent_lab/, and its tools/gecx_audio_lab/ compatibility implementation are local validation utilities. Their browser assets and development dependencies are installed through requirements-dev.txt and must not be copied to an EC2 gateway or included in an image or release archive. Gateway containers install only requirements.txt. Deploying the whole repository can cause host scanners to report development-only dependencies as if the gateway loaded them at runtime. The E2E caller can temporarily forward a private monitoring listener through an SSM-managed host so exact terminal outcomes are observed without publishing the monitoring API. Keep the instance ID, private host, region, profile, and ports in ignored local configuration; see the E2E caller guide.

Before deployment, scan the generated archive and verify its checksum. Keep environment configuration and secrets outside the artifact and inject them through the deployment system.

Build the ECS Container

Build the Fargate-compatible image for the ECS runtime architecture:

docker buildx build \
  --platform linux/amd64 \
  --load \
  -t byova-gateway:ecs-dev-local \
  .

The image uses the digest-pinned linux/amd64 Amazon Linux 2023 minimal base and its namespaced Python 3.12 package. It installs matching CPU-only Torch and Torchaudio packages, regenerates protobuf modules, runs as UID 10001, exposes gRPC 50051, WebSocket 8765, and monitoring 8080, and emits logs to standard output by default. The ECS task enables its init process instead of adding an init binary to the image. A short-lived, capability-limited init container assigns the writable runtime volume to UID 10001 before the capability-free gateway starts. The container bootstrap can fetch a private gateway YAML from GATEWAY_CONFIG_S3_URI. GECX on ECS preferably uses GOOGLE_EXTERNAL_ACCOUNT_S3_URI with Google workload-identity external_account configuration. For a dev migration, an existing service-account profile may instead be read directly from an exact Secrets Manager ARN. It is validated and written only to the task's ephemeral volume; it is never stored in the image, S3, or task environment. The container health check reads the selected transport mode and probes only its active listeners. In dual mode it requires both listeners unless the explicit development partial-startup option is enabled.

For a local container check, use config/container_smoke_example.yaml only on loopback or in a task that is not attached to a public listener. It intentionally disables JWT and datasource lifecycle and is not a deployment configuration.

Keep environment-specific orchestration, AWS resource identifiers, listener rules, private networking, and credential references outside this shared example repository.

Development

To add a connector:

  1. Create a connector class in src/connectors/.
  2. Inherit from IVendorConnector and implement every required method.
  3. Add the connector to config/config.yaml.
  4. Add unit and integration tests.
  5. Validate the full conversation lifecycle, including escalation and cleanup.

If a proto changes, regenerate the local Python modules:

python -m grpc_tools.protoc \
  -I./proto \
  --python_out=src/generated \
  --grpc_python_out=src/generated \
  proto/*.proto

Support and Contributing

For BYOVA concepts and onboarding, see the official BYOVA developer guide. For repository changes, open an issue or pull request with reproduction steps and relevant logs that do not contain credentials, caller audio, or customer data.

Maintainer: @adweeks

License

Cisco Sample Code License v1.1 © 2018 Cisco and/or its affiliates.

This sample code is not supported by Cisco TAC and is not tested for production quality or performance. It is provided for example purposes only, “AS IS,” with all faults and without warranty or support of any kind.

Releases

Packages

Contributors

Languages