docs: WxCC AI Agent ticket-operations reference

Adds a shareable reference doc covering everything the Contact Center
AI agent needs to open, look up, comment on, and close SS tickets via
this service:

  1. Inventory of the 9 AI-facing endpoints (read / create / update / close)
  2. The 14 supported SS subTypes (copy-pasteable)
  3. A drop-in system prompt (call-flow discipline, safety rules)
  4. Tool definitions in OpenAI/JSON-schema function-calling format
  5. Two worked call examples
  6. Endpoints deliberately kept out of the AI's tool loop

Companion to the code shipped in this branch — no code changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jmcqueen 2026-07-07 11:28:21 -04:00
parent 034e657fcb
commit e9a32e31c1

344
docs/wxcc-ai-agent-tools.md Normal file
View file

@ -0,0 +1,344 @@
# WxCC AI Agent — Ticket Operations Reference
Everything the Webex Contact Center AI agent needs to open, look up, comment
on, and close AEO Store Support (SS) Jira tickets via this service. Includes:
1. The full inventory of ticket-operation endpoints
2. The 14 supported SS subTypes
3. A drop-in system prompt for the AI agent
4. Tool definitions in OpenAI/JSON-schema function-calling format
5. Two worked call examples
6. Endpoints that are deliberately NOT exposed to the AI
All endpoints are under `/api/wxccai/` on the service (default port `1866`).
This doc covers the caller-facing surface only — admin/debug endpoints
(`/admin/caches/*`, `/debug/*`) and the Webex transcript webhook
(`/issueTranscript/:jiraKey`) are intentionally omitted here.
---
## 1. Ticket-operation inventory
### Read / lookup (safe, side-effect-free)
| # | Tool | Endpoint | What it does |
| - | ------------------- | --------------------------------------------------- | ------------ |
| 1 | `lookupTicket` | `GET /getticket?jiraKey=SS-12345` | Returns an **AI-summarized** view (Grok-generated) of a specific ticket: status, assignee, and a natural-language recap of the description + last 5 comments. Best for "tell me about my ticket" moments. |
| 2 | `findMyTickets` | `GET /open-tickets-by-reporter?email=user@ae.com` | Returns the caller's currently open tickets across CS/SS/SUPPORT with short summaries. Best for the opening beats of a call ("Do I already have a ticket for this?"). |
| 3 | `getTicketStatus` | `GET /ticket/:key/status` | Raw status fields (no Grok). Faster/cheaper than `lookupTicket`. Use when the AI just needs the current status, resolution, assignee — not a narrative. |
### Create (opens a new ticket)
| # | Tool | Endpoint | What it does |
| - | ------------------- | ---------------------------- | ------------ |
| 4 | `createStoreTicket` | `POST /createSSRequest` | Files a new Store Support (SS) ticket with the right subType, links it to a store via Assets, and returns the new key. Uses the 14 supported subTypes below. |
### Update (mid-conversation)
| # | Tool | Endpoint | What it does |
| - | --------------------- | ---------------------------------------- | ------------ |
| 5 | `addTicketComment` | `POST /ticket/:key/comment` | Appends a comment (public or `internal:true`). Internal is the safe default for AI-authored notes. |
| 6 | `updateTicketFields` | `PATCH /ticket/:key` | Update summary / description / priority / labels / assignee / custom fields. Rarely needed by the AI. |
### Close (three intent-specific + one full-control)
| # | Tool | Endpoint | What it does |
| - | ----------------------- | --------------------------------------------- | ------------ |
| 7 | `confirmTicketFixed` | `POST /ticket/:key/confirmFixed` | Caller says the issue is resolved → close with `resolution=Done` + audit comment. |
| 8 | `cancelTicket` | `POST /ticket/:key/customerCancelled` | Caller wants to abandon the request → close with `resolution=Won't Do`. |
| 9 | `markTicketDuplicate` | `POST /ticket/:key/duplicate` | Caller already has another ticket for the same issue → creates a formal `Duplicate` issueLink to the primary + closes with `resolution=Duplicate`. |
| — | `closeTicket` | `POST /ticket/:key/close` | Full-control close. Do NOT expose to the AI — use the intent-specific tools instead. |
All three close tools auto-populate the four workflow-validator fields
(Component, Business Service, System, Cause) from `subType`-based defaults
(see `src/config/ssCloseDefaults.js`), so the AI just supplies the ticket
key and the subType from the original create.
---
## 2. Supported SS subTypes (must match exactly)
The AI must pass one of these strings, unchanged. Casing and spacing
matter; duplicates in the list are intentional (both spellings are
mapped, but the AI should still copy exactly one of these strings).
```
Register Not functioning properly
Unable to login
Business report issue
Broken device / hardware
Broken Device / Hardware
Report Missing Hardware
Request Additional Hardware
Business Report Issue
Report an Issue with Sterling Application
Omni Turn Off / On
Report a Traffic Counter Issue
Report a Technology issue
UKG Pro / Workforce Management Issues
Store Transportation Request
```
If none of these clearly fit the caller's issue, use
**`Report a Technology issue`** as the catch-all.
---
## 3. System prompt (paste into the WxCC AI Agent config)
```text
You are a Store Support (SS) AI agent for AEO stores. You handle inbound
calls from store associates and managers who need technology help. Your job
is to identify the caller, understand their issue, and either open, update,
or close the appropriate Jira ticket.
CORE PRINCIPLES
1. Never invent ticket keys, store numbers, or subTypes. If the caller
doesn't volunteer one, ask.
2. Store numbers are always 5 digits (pad with leading zeros: "305" →
"00305").
3. Never call a close tool (confirmTicketFixed, cancelTicket,
markTicketDuplicate) based on inference alone. The caller must
explicitly state the intent in the current turn.
4. When in doubt, add an internal comment (addTicketComment with
internal=true) and escalate to a human. Never close a ticket you're
unsure about — an open ticket costs the business less than a wrongly
closed one.
5. For every ticket action, the caller's email is required to identify
them as the reporter.
TYPICAL CALL FLOW
Step 1: Identify the caller.
- Ask for or confirm their email + store number.
- Call findMyTickets with their email to see what's already open.
Step 2: Decide what they need.
- If they reference a specific existing ticket → lookupTicket for a
summary; then decide with them what to do next (comment, close, or
just answer their question).
- If they describe a new issue → pick the best subType from the fixed
list (see the createStoreTicket tool description) and call
createStoreTicket.
- If it's a mix ("my existing ticket X is fixed but now Y is broken")
→ handle in order: close the resolved one first, then create the new
one.
Step 3: Close at the right moment, with the right tool.
- "It's already fixed" / "the manager rebooted it and it works now"
→ confirmTicketFixed
- "Never mind" / "cancel it" / "I don't need this anymore"
→ cancelTicket
- "I already opened SS-12345 for this" / "this is the same as SS-XXX"
→ markTicketDuplicate (you must have the primaryKey)
- Anything ambiguous → addTicketComment describing the ambiguity and
escalate.
Step 4: Always confirm the action back to the caller.
- After createStoreTicket, read back the new ticket key.
- After any close tool, tell them the ticket is closed and why.
WHAT NOT TO DO
- Do NOT expose Jira internals (customfield IDs, objectTypeIds, workflow
transition IDs) to the caller.
- Do NOT call closeTicket (the raw endpoint). Always use one of the three
intent-specific tools.
- Do NOT call updateTicketFields unless the caller explicitly asks to
change something structural (priority, assignee).
- Do NOT re-open a ticket you just closed in the same call. If you closed
by mistake, escalate to a human.
```
---
## 4. Tool definitions (OpenAI / JSON-schema function-calling format)
Adjust the wrapper syntax to whatever WxCC expects; the JSON schema is
standard and portable across most LLM tool-calling frameworks.
```json
[
{
"name": "findMyTickets",
"description": "Look up the caller's currently open tickets across CS/SS/SUPPORT projects. Call this near the start of every conversation once you have the caller's email, so you know what's already in flight before opening a new ticket. Returns a list of {key, summary, status, updated}.",
"parameters": {
"type": "object",
"properties": {
"email": { "type": "string", "description": "Caller's work email address (e.g. someone@ae.com)." }
},
"required": ["email"]
},
"http": { "method": "GET", "path": "/api/wxccai/open-tickets-by-reporter", "queryParams": ["email"] }
},
{
"name": "lookupTicket",
"description": "Fetch an AI-summarized view of a specific ticket (title, status, assignee, and a natural-language recap of the description + last 5 comments). Use when the caller references an existing ticket by key and you need context before taking action.",
"parameters": {
"type": "object",
"properties": {
"jiraKey": { "type": "string", "description": "Jira issue key, e.g. SS-20948." }
},
"required": ["jiraKey"]
},
"http": { "method": "GET", "path": "/api/wxccai/getticket", "queryParams": ["jiraKey"] }
},
{
"name": "getTicketStatus",
"description": "Get raw status/assignee/resolution/priority fields for a ticket without the AI summary. Faster than lookupTicket. Use when you just need to check whether a ticket is Open/In Progress/Resolved.",
"parameters": {
"type": "object",
"properties": {
"key": { "type": "string", "description": "Jira issue key, e.g. SS-20948." }
},
"required": ["key"]
},
"http": { "method": "GET", "path": "/api/wxccai/ticket/{key}/status", "pathParams": ["key"] }
},
{
"name": "createStoreTicket",
"description": "Open a new Store Support (SS) ticket. Use ONLY when the caller has a new issue that isn't already covered by one of their existing open tickets (check findMyTickets first). Choose the subType that best matches the caller's issue from the fixed list. If none of the listed subTypes fit, use 'Report a Technology issue' as the catch-all.",
"parameters": {
"type": "object",
"properties": {
"subType": {
"type": "string",
"enum": [
"Register Not functioning properly",
"Unable to login",
"Business report issue",
"Broken device / hardware",
"Broken Device / Hardware",
"Report Missing Hardware",
"Request Additional Hardware",
"Business Report Issue",
"Report an Issue with Sterling Application",
"Omni Turn Off / On",
"Report a Traffic Counter Issue",
"Report a Technology issue",
"UKG Pro / Workforce Management Issues",
"Store Transportation Request"
],
"description": "Exact subType string. Must match one of the enum values."
},
"onBehalfOf": { "type": "string", "description": "Caller's email address." },
"summary": { "type": "string", "description": "One-line title of the issue. Concise, action-oriented." },
"description":{ "type": "string", "description": "Detailed narrative. Include what the caller was doing, what went wrong, and any error messages they read to you." },
"storeNumber":{ "type": "string", "description": "5-digit store number (pad with leading zeros: '305' -> '00305')." }
},
"required": ["subType", "onBehalfOf", "summary", "storeNumber"]
},
"http": { "method": "POST", "path": "/api/wxccai/createSSRequest", "body": "json" }
},
{
"name": "addTicketComment",
"description": "Append a comment to an existing ticket. Use to record mid-call context, escalation reasons, or anything the caller says that a downstream human agent will need. Default to internal=true for AI-authored notes; only set internal=false when the caller has asked for a public/customer-visible update.",
"parameters": {
"type": "object",
"properties": {
"key": { "type": "string", "description": "Jira issue key." },
"text": { "type": "string", "description": "Comment body, plain text." },
"internal": { "type": "boolean", "description": "true = visible only to the Service Desk Team (default, recommended). false = visible to the customer.", "default": true }
},
"required": ["key", "text"]
},
"http": { "method": "POST", "path": "/api/wxccai/ticket/{key}/comment", "pathParams": ["key"], "body": "json" }
},
{
"name": "confirmTicketFixed",
"description": "Close a ticket because the caller has EXPLICITLY confirmed the underlying issue is resolved (e.g. 'the manager rebooted it and it works now', 'yeah I got it working'). Do not use this to close a ticket the caller is ambivalent or silent about. Adds a standardized 'Closed via WxCC AI agent: caller confirmed the issue is resolved.' internal comment automatically.",
"parameters": {
"type": "object",
"properties": {
"key": { "type": "string", "description": "Jira issue key being closed." },
"subType": { "type": "string", "description": "The original subType the ticket was opened under. Same enum as createStoreTicket. Used to pick the right classification defaults for the workflow validator." },
"comment": { "type": "string", "description": "Optional extra context to append to the standardized close comment." }
},
"required": ["key", "subType"]
},
"http": { "method": "POST", "path": "/api/wxccai/ticket/{key}/confirmFixed", "pathParams": ["key"], "body": "json" }
},
{
"name": "cancelTicket",
"description": "Close a ticket because the caller has EXPLICITLY asked to cancel it (e.g. 'nevermind, cancel it', 'I don't need this anymore', 'I opened this by mistake'). Records the caller's reason if they gave one. Resolution is set to 'Won't Do'.",
"parameters": {
"type": "object",
"properties": {
"key": { "type": "string", "description": "Jira issue key being cancelled." },
"subType": { "type": "string", "description": "The original subType. Used to pick classification defaults." },
"reason": { "type": "string", "description": "Optional reason the caller gave for the cancellation." }
},
"required": ["key", "subType"]
},
"http": { "method": "POST", "path": "/api/wxccai/ticket/{key}/customerCancelled", "pathParams": ["key"], "body": "json" }
},
{
"name": "markTicketDuplicate",
"description": "Close a ticket because the caller told you it's a duplicate of another existing ticket. Requires BOTH the ticket being closed (key) AND the primary ticket it duplicates (primaryKey). Creates a formal 'Duplicate' link between them in Jira, then closes with resolution 'Duplicate'. If the caller isn't sure of the primary key, do NOT guess — use findMyTickets to help them identify it, or fall back to addTicketComment + escalate.",
"parameters": {
"type": "object",
"properties": {
"key": { "type": "string", "description": "Jira key of the ticket being closed as a duplicate." },
"primaryKey": { "type": "string", "description": "Jira key of the primary/canonical ticket this one duplicates." },
"subType": { "type": "string", "description": "The original subType of the duplicate ticket. Used to pick classification defaults." },
"comment": { "type": "string", "description": "Optional extra context to append to the standardized close comment." }
},
"required": ["key", "primaryKey", "subType"]
},
"http": { "method": "POST", "path": "/api/wxccai/ticket/{key}/duplicate", "pathParams": ["key"], "body": "json" }
}
]
```
---
## 5. Worked call examples
### Example 1 — new issue, straightforward create
```
Caller: "Hi, register 3 at store 782 froze during checkout."
AI: [findMyTickets email="jane@ae.com"] → no open tickets
AI: [createStoreTicket
subType="Register Not functioning properly",
onBehalfOf="jane@ae.com",
summary="Register 3 froze at checkout",
description="Caller reports register 3 became unresponsive during a
transaction around 10:15am. No error message read to
the caller.",
storeNumber="00782"]
→ returns { issueKey: "SS-20955" }
AI: "I've opened ticket SS-20955 for you. The store technology team
will pick it up shortly."
```
### Example 2 — caller wants to close an existing ticket
```
Caller: "Hey, I opened SS-20948 yesterday but the manager fixed it — can
you close it out?"
AI: [getTicketStatus key="SS-20948"] → status: "Open"
AI: "Just to confirm, SS-20948 for the [issue description] — the
issue is fully resolved and you don't need us to look at it
anymore?"
Caller: "Yep, all good."
AI: [confirmTicketFixed
key="SS-20948",
subType="Report a Technology issue",
comment="Caller reports issue resolved on-site by store manager."]
→ returns { success: true, transitionUsed: "Resolved", resolution: "Done" }
AI: "Perfect, SS-20948 is now closed as resolved. Anything else?"
```
---
## 6. Deliberately NOT exposed to the AI
Reserved for humans / ops / internal plumbing:
- `updateTicketFields` (`PATCH /ticket/:key`) — too much surface area; humans should handle structural edits.
- `closeTicket` (raw `POST /ticket/:key/close`) — the three intent-specific tools are safer; they auto-populate the workflow validator and audit comment.
- `getTransitions` (`GET /ticket/:key/transitions`) — internal plumbing; the close tools use it under the hood.
- `/admin/caches/*`, `/debug/*` — cache and diagnostic endpoints.
- `/issueTranscript/:jiraKey` — Webex Contact Center webhook target, called by the platform rather than by the AI agent's tool loop.