Webex Contact Center AI Agent Helper Bot
- wxccRoutes.js no longer mutates the default axios instance, which was causing every bare axios call in the codebase (S3 downloads, Assets diagnostics) to inherit retries as a side-effect of route file load order. - jiraService.js now defines a private downloadClient (own timeout, own retry policy) used by attachFileToJira and fetchAndConvertTranscript for fetching pre-signed S3 URLs. - Assets AQL/GET remain bare axios calls; they're one-shot diagnostics and should not auto-retry. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|---|---|---|
| src | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| discover-ss-fields.js | ||
| discover-ss-request-types.js | ||
| docker-compose.yml | ||
| Dockerfile | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| ss-fields-266.json | ||
| ss-fields-267.json | ||
| ss-fields-268.json | ||
| ss-fields-269.json | ||
| ss-fields-270.json | ||
| ss-fields-271.json | ||
| ss-fields-272.json | ||
| ss-fields-273.json | ||
| ss-fields-274.json | ||
| ss-fields-275.json | ||
| ss-fields-426.json | ||
| ss-fields-493.json | ||
| ss-request-types-clean.json | ||
| ss-request-types.json | ||
wxcc-ai
Node/Express service that wires Webex Contact Center summaries, Jira tickets (core + JSM Store Support), and xAI Grok summarization into a single set of internal HTTP endpoints.
Setup
npm install
cp .env.example .env
# fill in JIRA_*, XAI_*, and optionally the Assets values
npm run dev
The server listens on PORT (default 1866).
Environment variables
See .env.example for the full list. The important ones:
| Var | Purpose |
|---|---|
JIRA_CLOUD_ID |
If set, requests use https://api.atlassian.com/ex/jira/{cloudId}. |
JIRA_BASE_URL |
Fallback for legacy site URLs (https://your-site.atlassian.net). |
JIRA_EMAIL, JIRA_API_TOKEN |
Basic auth to Jira. JIRA_AUTH_TYPE=bearer switches to bearer. |
JIRA_SERVICE_DESK_ID |
Numeric JSM service desk id for Store Support. |
JIRA_ASSETS_WORKSPACE_ID |
Assets workspace id (auto-discovered if omitted). |
JIRA_ASSETS_STORE_SCHEMA_ID, _OBJECT_TYPE_ID |
Locate the Store schema/type. |
JIRA_ASSETS_STORE_NUMBER_ATTRIBUTE[_ID] |
Attribute name (or id) holding the store number in Assets. |
JIRA_STORE_CUSTOM_FIELD_ID |
Custom field on the JSM request that holds the Store Assets reference. |
XAI_API_KEY, XAI_BASE_URL |
Grok credentials for summary generation. |
Endpoints
Base path: /api/wxccai.
Read
GET /getticket?jiraKey=CS-1234— Grok-summarized single ticket.GET /open-tickets-by-reporter?email=user@example.com— Grok-summarized list of open tickets a person reported.GET /ticket/:key/status— raw status fields (no Grok).GET /ticket/:key/transitions— available workflow transitions.
Write
PATCH /ticket/:key— body:{ summary?, description?, priority?, labels?, assigneeAccountId?, additional? }POST /ticket/:key/comment— body:{ text, internal? }POST /ticket/:key/close— body:{ transitionName?, resolution?, comment?, internal? }(auto-picks the first "done" transition whentransitionNameomitted).
Store Support (JSM requests)
GET /ssRequestTypes— supportedsubTypevalues + Assets config summary.POST /createSSRequest— body includessubType,summary,storeNumber(auto-resolved via Assets),onBehalfOf,description,additional.
Webex webhook
POST /issueTranscript/:jiraKey— attaches audio + JSON transcript + human-readable transcript, then posts a restricted-visibility summary comment.
Debug (non-production only)
GET /debug/assetsProbe?storeNumber=305— runs several AQL variants against Jira Assets and returns visible schemas + object-type detail + a computed diagnosis. Returns 404 whenNODE_ENV=production.
Jira Assets gotcha
createSSRequest resolves a store number to an Assets object reference (customfield_10261). Two independent permission layers must both grant access, or every AQL query silently returns total: 0:
- OAuth scopes on the API token:
read:cmdb-schema:jira,read:cmdb-type:jira,read:cmdb-object:jira,read:cmdb-attribute:jira(and thewrite:equivalents for updates). - Object Schema role membership in Jira Assets itself — the underlying user needs to be added to a role on the Store schema in Jira → Assets → Object schemas → Configure → Roles.
If AQL keeps returning total: 0 with HTTP 200, run the probe endpoint above; the diagnosis field will tell you exactly which layer is missing.
Docker
npm run docker:build
npm run docker:run
The image runs as a non-root user and exposes 1866. HEALTHCHECK pings GET /health.
Repo hygiene
- Secrets live only in
.env, which is.gitignored. - The two
discover-ss-*.jshelper scripts read from.env— never hardcode credentials in them. - The debug logger no longer echoes the outbound
Authorizationheader. Rotate any token that appears in olderlogs/*.logfiles.