Webex Contact Center AI Agent Helper Bot
Find a file
jmcqueen c4a0a6934e Fix #4: remove global axios-retry side-effect; add dedicated downloadClient
- 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>
2026-07-01 16:28:47 -04:00
src Fix #4: remove global axios-retry side-effect; add dedicated downloadClient 2026-07-01 16:28:47 -04:00
.dockerignore Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
.env.example Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
.gitignore Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
discover-ss-fields.js Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
discover-ss-request-types.js Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
docker-compose.yml Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
Dockerfile Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
package-lock.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
package.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
README.md Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-266.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-267.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-268.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-269.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-270.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-271.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-272.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-273.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-274.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-275.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-426.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-fields-493.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-request-types-clean.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00
ss-request-types.json Initial commit: Webex CC + Jira + xAI service 2026-07-01 15:23:20 -04:00

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 when transitionName omitted).

Store Support (JSM requests)

  • GET /ssRequestTypes — supported subType values + Assets config summary.
  • POST /createSSRequest — body includes subType, 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 when NODE_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:

  1. OAuth scopes on the API token: read:cmdb-schema:jira, read:cmdb-type:jira, read:cmdb-object:jira, read:cmdb-attribute:jira (and the write: equivalents for updates).
  2. 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-*.js helper scripts read from .env — never hardcode credentials in them.
  • The debug logger no longer echoes the outbound Authorization header. Rotate any token that appears in older logs/*.log files.