Knowledge Base · MSP Operations
Agent Metrics
Dashboard
Complete reference for the Agent Metrics Dashboard — live performance monitoring for deployed AI agents pulling resolution and escalation data from ConnectWise Manage and Copilot usage from the Microsoft Graph API. Feeds the Agent Benchmark Log via one-click sync.
CW MANAGE M365 COPILOT GRAPH API BENCHMARK SYNC

The Agent Metrics Dashboard is the live data layer for the MSP AI Platform agent performance program. It replaces manual data collection by pulling four of the six benchmark metrics directly from ConnectWise Manage and Microsoft Graph, then packaging them for import into the Agent Benchmark Log.

This tool does not replace the Agent Benchmark Log — it feeds it. The benchmark log is the governance record. This dashboard is the data source.

Automated Metrics
  • Resolution rate from CW Manage ticket disposition
  • Escalation rate from post-AI assignment history
  • Time saved from CW open-to-close timestamps
  • Cost per interaction from Copilot seat licensing and Graph interaction count
Always Manual
  • Accuracy — requires human spot-check of 20-30 ticket sample
  • User satisfaction — requires survey from end users
  • Both shown as badges in the dashboard: "Spot-check required" and "Survey pending"
Step 1 — CW Manage Custom Field

In ConnectWise Manage go to Setup Tables → Custom Fields → Service Ticket. Create a Text field (100 chars) with this exact caption:

text
Field caption: AI_Agent
Field type:    Text (100 characters)

When an AI agent handles a ticket, the agent writes its identifier to this field. Values must match the cwTag in the AGENTS config array exactly — case-sensitive.

A mismatch between the field value and the AGENTS config returns zero results silently. No error is shown.
Step 2 — Four Azure Function Proxy Routes
/api/cw-tickets→ CW Manage /service/tickets filtered on AI_Agent custom field. Returns ticket list for volume, close time, and assignment history. Auth: Basic (CompanyId+PublicKey:PrivateKey).
/api/cw-count→ CW Manage /service/tickets/count. Same conditions. Returns integer count for quick stats.
/api/graph-copilot→ Graph getMicrosoft365CopilotUsageSummary(period='D30'). Active users, interactions, feature breakdown. Auth: Bearer via Managed Identity.
/api/graph-users→ Graph getMicrosoft365CopilotUsageUserDetail(period='D30'). Per-user per-feature activity. Auth: Bearer via Managed Identity.
Step 3 — Graph Permissions

Grant the Function Managed Identity Reports.Read.All application permission in Azure AD. Admin consent required.

bash
az ad app permission add \
  --id  \
  --api 00000003-0000-0000-c000-000000000000 \
  --api-permissions 230c1aed-a721-4c5d-9cb4-a90514e508ef=Role

az ad app permission admin-consent --id 
Step 4 — Config Block

Update the config block at the top of the script before setting DEMO_MODE to false:

javascript
var DEMO_MODE         = false;  // change last, after all else is validated
var PROXY_BASE        = 'https://.azurewebsites.net/api';
var COPILOT_SEATS     = 60;    // your licensed Copilot seat count
var COPILOT_SEAT_COST = 30;   // monthly cost per seat in USD
Setup Notice Strip

Collapsible yellow strip containing the four setup steps with exact field names and Azure CLI commands. Collapse once setup is complete.

Proxy Wiring Table

Four-cell table documenting exact proxy routes, target endpoints, auth methods, and pass-through parameters. Build spec for the Azure Function configuration.

Agent Tab Bar

One tab per agent plus "All Agents". Each tab has a RAG dot. Selecting a tab filters all panels to that agent's data.

Summary Strip
Resolution RateResolved tickets (no reassignment after AI stamp) ÷ total AI-tagged tickets
Escalation RateTickets assigned to human after AI stamp ÷ total AI-tagged tickets
Avg Time Saved / TicketHuman avg close time minus AI avg close time for same ticket type
Cost / Interaction(COPILOT_SEATS × COPILOT_SEAT_COST) ÷ total Copilot interactions in period
AI Tickets (30d)Total tickets with AI_Agent field populated in the last 30 days
CW Manage Metrics Panel

Left panel. Bar chart rows for each metric with current value, RAG color, and baseline delta. Accuracy and satisfaction shown as manual badges — not calculated.

Copilot Usage Panel

Right panel. Active users, total interactions, seat cost, and cost per interaction. Feature usage breakdown (Teams, Outlook, Word, Excel, etc.). Cost formula callout at the bottom.

Ticket Feed

Live table of AI-tagged tickets: ID, summary, agent tag, status chip (resolved/escalated/open), AI close time, date. Filtered to selected agent. 10 rows max.

Sync Bar

"Sync to Benchmark Log" button and last-synced timestamp. Packages the four auto-calculated metrics into a JSON payload and writes to localStorage.

Resolution RateClosed tickets with no resource reassignment after AI_Agent stamp ÷ total AI-tagged tickets in 30-day window × 100
Escalation RateTickets with a human resource assigned after AI_Agent stamp ÷ same denominator × 100
Time Saved / TicketCW Manage dateResolved − dateEntered for AI-tagged tickets vs same metric for non-AI tickets of same type. Difference = time saved per ticket.
Cost / InteractionCopilot is seat-licensed not token-billed. Monthly cost = COPILOT_SEATS × $30. Divide by Graph total interactions for per-interaction cost.
AccuracyNot calculated. Pull 20-30 random agent-handled tickets monthly and score correct/incorrect. Enter result manually in the benchmark log.
SatisfactionNot calculated. Collect post-interaction ratings (1-5). Average the responses. Enter manually in the benchmark log.
The "Spot-check required" and "Survey pending" badges are intentional — no API can reliably determine output quality or user sentiment.

The sync operation bridges live data with the governance record. It pre-fills the log entry form — you review before saving.

Sync Flow
  • Click "Sync to Benchmark Log" in the sync bar
  • JSON payload written to localStorage["msp-benchmark-sync"]
  • Open tools/tl-agent-benchmark-log.html in the same browser
  • Green banner appears: "Metrics from API Dashboard Ready"
  • Click "Import and Pre-fill Entry" — entry modal opens with four fields pre-filled
  • Enter accuracy (spot-check result) and satisfaction (survey average) manually
  • Notes field auto-records sync source and date
  • Click Save — entry logged with full attribution
javascript
// Payload structure written to localStorage
{
  agentHint: "IVR-Triage",
  date:      "2025-05-18",
  source:    "API Dashboard — CW Manage + M365 Copilot",
  metrics: { res: 82.3, esc: 17.7, time: 3.1, cost: 0.021, acc: null, sat: null },
  notes:     "Auto-synced from Agent Metrics Dashboard on May 18, 2025..."
}
The sync key is cleared after import. Dismiss the banner without importing and you must sync again.

DEMO_MODE at the top of the script block controls the data source. The "Switch to Live" button in the header toggles it at runtime.

DEMO_MODE = true (default)All data from mock functions. No API calls. Safe for UI testing and demos.
DEMO_MODE = falseAll data from proxy. Requires PROXY_BASE set and all four proxy routes deployed.
Runtime toggleDoes not persist across reloads. Update the source file to permanently enable live mode.
Live mode makes real API calls every 30 seconds. Test all proxy routes in demo mode first before switching.

Edit the AGENTS array to match your deployed agents. The cwTag must exactly match the CW custom field value — case-sensitive.

javascript
var AGENTS = [
  { id: 'all',               label: 'All Agents',        cwTag: null },
  { id: 'IVR-Triage',        label: 'IVR Triage',        cwTag: 'IVR-Triage' },
  { id: 'NOC-Summarizer',    label: 'NOC Summarizer',    cwTag: 'NOC-Summarizer' },
  { id: 'Ticket-Classifier', label: 'Ticket Classifier', cwTag: 'Ticket-Classifier' },
];
CW tickets show 01. Verify AI_Agent custom field exists with exact caption. 2. Confirm at least one ticket has the field populated. 3. Check the /api/cw-tickets proxy route is deployed and CW credentials are in Key Vault.
Graph API returns 403Function Managed Identity needs Reports.Read.All with admin consent in Azure AD.
Cost shows $0.000COPILOT_SEATS is 0 in the config block. Update to your licensed seat count.
Sync banner not appearing in benchmark logConfirm both tools are open in the same browser profile (same origin). Check that localStorage is not blocked.
nav.js 404Place nav.js one directory above dashboards/ or update the script src to an absolute URL.