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.
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
ListVirtualAgentsandProcessCallerInput - BYOVA WebSocket
/v1/vaand/v1/listVirtualAgentsendpoints 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
CHUNKoutput 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 orderedFINALper 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
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.
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
ACTIVEBYOVA 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.
- Python 3.8 or later
- macOS, Linux, or Windows
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/*.protoOn Windows, activate the virtual environment with venv\Scripts\activate.
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: falseNever 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.
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.
python main.pyThen check:
curl http://localhost:8080/api/status
python test_health.pyThe 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.
| 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.
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.
/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.
GET /: Development monitoring dashboardGET /api/status: Gateway and connector statusGET /api/connections: Recent connection informationGET /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.
- 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) andAWSLexWebSocketConnector(WxCC WebSocket) adapters share Amazon Lex V2RecognizeUtterance, 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.GECXConnectoruses the CES gRPC client;GECXWebSocketConnectoruses 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.
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 EC2 and server releases with the allowlisted runtime artifact builder:
scripts/build-runtime-release.sh \
--ref HEAD \
--output /tmp/byova-gateway-runtime.tar.gzThe 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 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.
To add a connector:
- Create a connector class in
src/connectors/. - Inherit from
IVendorConnectorand implement every required method. - Add the connector to
config/config.yaml. - Add unit and integration tests.
- 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/*.protoFor 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
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.