ideas/Ticket-Routing.ps1
|
#requires -Version 7.0 # Set TYPESAFE_API_KEY before running this live example. Import-Module (Join-Path $PSScriptRoot '..' 'Jev.psd1') -Force # ── Call-through functions ───────────────────────────────────────── # Stand-ins for real routing logic — replace bodies with actual # ticketing/Slack/PagerDuty calls when ready. Each returns the # routing message so it can be attached to the decision object. function Invoke-RetentionEscalation { param( [Parameter(Mandatory)] $Ticket ) "[RETENTION ESCALATION] Ticket: $Ticket" } function Invoke-OnCallRoute { param( [Parameter(Mandatory)] $Ticket ) "[ON-CALL] Paging on-call engineer for ticket: $Ticket" } function Invoke-QueueRoute { param( [Parameter(Mandatory)] [string] $Category, [Parameter(Mandatory)] $Ticket ) "[QUEUE: $Category] Routed ticket: $Ticket" } function Invoke-HumanTriage { param( [Parameter(Mandatory)] $Ticket, [string] $Reason = 'Needs clarification' ) "[HUMAN TRIAGE] Ticket: $Ticket — $Reason" } # ── Core entry point ───────────────────────────────────────────────── function Resolve-TicketRouting { param( [Parameter(Mandatory)] [string] $Ticket, [Parameter(Mandatory)] [string] $State, [ValidateRange(0, 1)] [double] $ConfidenceThreshold = 0.6 ) $questions = @( New-JevQuestion -Name urgency -Type Score ` -Instructions 'How urgent is the operational response? Reserve Critical for an active production outage or widespread failure needing immediate on-call engineering.' ` -Criteria @( 'Can wait.' 'Needs attention this week.' 'Needs attention today, but no production outage.' 'Active production outage or widespread failure requiring immediate on-call engineering.' ) New-JevQuestion -Name category -Type Choice ` -Instructions 'Which category is supported by the details in this ticket? Choose unclear when the message does not identify the issue well enough to route it.' ` -Criteria @{ billing = 'Billing or invoicing issue' bug = 'Product defect or error' feature_request = 'Request for new functionality' account_access = 'Login, permissions, or access issue' unclear = 'The message is too vague or mixes possible issues; ask for more details.' } New-JevQuestion -Name needsClarification -Type Noul ` -Instructions 'Is there too little information to identify the actual issue and route this ticket?' ` -Criteria @{ true = 'The issue is unclear or several different issues are plausible.' false = 'The issue is specific enough to route.' } New-JevQuestion -Name churnRisk -Type Score ` -Instructions 'How likely is this customer to churn?' ` -Criteria @('Low', 'Medium', 'High') ) $decision = Invoke-Jev -State $State -Question $questions $categoryConfidence = [double] $decision.answers.category.confidence $clarificationProbability = [double] $decision.answers.needsClarification.noul # Score is a numeric average of levels. Criteria start at index 0, so # churn level 2 is High and urgency level 3 is Critical. $highChurnProbability = [double] $decision.answers.churnRisk.probabilities.'2' $criticalProbability = [double] $decision.answers.urgency.probabilities.'3' if ($decision.category -eq 'unclear' -or $clarificationProbability -ge 0.5 -or $categoryConfidence -lt $ConfidenceThreshold) { $routingResult = Invoke-HumanTriage -Ticket $Ticket -Reason 'Issue needs clarification before routing' } elseif ($criticalProbability -ge 0.5) { $routingResult = Invoke-OnCallRoute -Ticket $Ticket } elseif ($highChurnProbability -ge 0.5) { $routingResult = Invoke-RetentionEscalation -Ticket $Ticket } else { $routingResult = Invoke-QueueRoute -Category $decision.category -Ticket $Ticket } $decision | Add-Member -NotePropertyName Ticket -NotePropertyValue $Ticket -Force $decision | Add-Member -NotePropertyName CategoryConfidence -NotePropertyValue $categoryConfidence -Force $decision | Add-Member -NotePropertyName ClarificationProbability -NotePropertyValue $clarificationProbability -Force $decision | Add-Member -NotePropertyName HighChurnProbability -NotePropertyValue $highChurnProbability -Force $decision | Add-Member -NotePropertyName CriticalProbability -NotePropertyValue $criticalProbability -Force $decision | Add-Member -NotePropertyName RoutingResult -NotePropertyValue $routingResult -Force return $decision } # ── Usage ──────────────────────────────────────────────────────────── # $ticketState = @' # Customer: enterprise tier, 3yr tenure, $80k ACV # Message: "This is the third time billing has charged us wrong. # If this isn't fixed today I'm escalating to our exec sponsor." # Recent tickets: 2 billing disputes in last 30 days # '@ # $result = Resolve-TicketRouting -Ticket 'TICKET-4821' -State $ticketState # $result # Target routes illustrate the policy; model judgments can vary between runs. $testTickets = @( @{ Ticket = 'TICKET-1001' State = @' Customer: enterprise tier, 3yr tenure, $80k ACV Message: "This is the third time billing has charged us wrong. If this isn't fixed today I'm escalating to our exec sponsor." Recent tickets: 2 billing disputes in last 30 days '@ Expected = 'RetentionEscalation (high churn probability)' } @{ Ticket = 'TICKET-1002' State = @' Customer: mid-market, 6mo tenure. Message: "Production is completely down, our checkout page returns a 500 error for every customer. We are losing sales right now." Severity: all users affected, no workaround. '@ Expected = 'OnCallRoute (critical urgency probability)' } @{ Ticket = 'TICKET-1003' State = @' Customer: small business, 1yr tenure. Message: "Could you add a dark mode option to the dashboard? Not urgent, just a nice-to-have for our team." No prior tickets. '@ Expected = 'QueueRoute (category=feature_request, low urgency, low churn)' } @{ Ticket = 'TICKET-1004' State = @' Customer: unspecified tier. Message: "hey it broke again i think, not sure, maybe billing? or login? kind of confusing today" No other details provided. '@ Expected = 'HumanTriage (issue needs clarification)' } ) foreach ($t in $testTickets) { Write-Host "`n=== $($t.Ticket) — target: $($t.Expected) ===" -ForegroundColor Cyan $result = Resolve-TicketRouting -Ticket $t.Ticket -State $t.State $result } |