Classification and routing

Classification and routing rules grow into switch statements.

Every new category, queue or exception adds another case, keyword list or condition to a method only developers can change. With IntentSharp the policy is written in plain words in an intent file, and the answer comes back as values of your own enums, checked before your code routes anything.

What it costs today

Routing starts as a switch on a few keywords. Then come the exceptions: an outage that only matters when it stops a whole site, a billing question that is really a sign-in problem, a customer whose tickets always go to one team. Each one is another branch, keyword list or regular expression, and each misses the phrasings nobody thought of.

The policy lives in code the support team cannot read, so every change to it is a ticket, a build and a deployment, and nobody outside development can check the rules the queues follow.

How IntentSharp handles it

The policy is in Support.Route.intent.yaml, in plain words, with one example. Its shape is TicketRoute, a record of two enums your application registers. Three tickets go through the same call; the third ticket's first answer names a queue the enum does not have, so it fails the check, and the second attempt routes it to Product.

Support.Route.intent.yamlIntent file
name: Support.Routeversion: 4owner: support-opsintent: >-  Read this support request and set its category, then its queue.  Billing goes to Finance, Access to Identity, Feature to Product  and Outage to Engineering, except an outage that stops a whole  site, which goes to Escalations.shape: { clrType: TicketRoute }examples:  - input: "Since the update nobody in our team can sign in."    output: { category: Access, queue: Identity }
Program.cs
// TicketRoute holds your two enums. A file may name it as its// shape because your application registered it.var types = new IntentTypeRegistry().Add<TicketRoute>();var intents = new IntentRuntime(client, catalog, types: types);var queues = Enum.GetValues<SupportQueue>()    .ToDictionary(queue => queue, _ => new List<string>()); foreach (var ticket in tickets){    var route = await ticket.RunIntentAsync<TicketRoute>(        intents, "Support.Route");    // No switch: a successful answer is a value of your enum.    if (route.Success) queues[route.Value!.Queue].Add(ticket);    results.Add(route);}
Output: three tickets, three queues
"We were charged twice for invoice INV-2291."  Success: true, after 1 attempt  Category: Billing, queue: Finance"The scanners in our whole warehouse cannot reach your service. Nothing ships."  Success: true, after 1 attempt  Category: Outage, queue: Escalations"Could you add an export to Excel on the orders page?"  Attempt 1 passed: false, one Verification finding  Success: true, after 2 attempts  Category: Feature, queue: Product Queues: Finance 1, Product 1, Escalations 1

TicketRoute is (TicketCategory Category, SupportQueue Queue): Billing, Outage, Access or Feature, and Finance, Engineering, Identity, Product or Escalations. Compiled and run with every build of this site; the model's answers are scripted, and a pass means the answer met the checks, not that the judgement is right.

What stays in your control

The file holds the policy. The enums, the queues and what happens to a ticket stay in your code.

  • Your enums are the only answers. Enum values are read by name. A name that is not a member of your enum fails the check and goes back to the model with the finding, and Value holds only an answer that passed.
  • The policy in plain words. The file's intent and examples steer the answer, and a saved edit applies to the next call. A reply that copies an example and breaks a rule still fails.
  • More checks where a rule can say it. The file can add rules, and your application can register C# checks that the file switches on under validators.
  • What a failure looks like. When the attempts run out, Success is false, Issues says why, and the ticket is yours to handle: in the program above, only a successful answer puts a ticket in a queue.
  • A pass is not a proof. A pass means the checks passed, not that the judgement is right. Each ticket is a model call, plus one per retry; for a fixed set of labels at high volume, a classifier you train yourself may cost less per call.

Route your next ticket from a file.

dotnet add package IntentSharp --prerelease
dotnet add package IntentSharp.Catalog --prerelease