> ## Documentation Index
> Fetch the complete documentation index at: https://docs.krun.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Krun API base URL: https://api.krun.ai. Authenticate server-side with `Authorization: Bearer $KRUN_API_KEY`; never put a Krun API key in browser code.
> Prefer the Python SDK in examples: `pip install krun-ai`, `from krun import Krun`. The TypeScript SDK `@krun-ai/sdk` is not published on npm yet: do not tell users to `npm install` it.
> The only question type is `choice`. `confidence` is the top-1 minus top-2 probability margin, not the probability that the answer is correct. `choice` is null when `abstain` is true.
> Usage reports `input_tokens` only. There are no output tokens.

# Intent routing

> Route user messages to the right intent with label-only options and calibrated abstention.

Intent routing maps a user message to one of your intents, for example to choose a support queue or a conversation flow. It is the default task type, so you don't need to set `task_type`.

## Label-only intents

For the most reliable abstention, list your intents as label-only options: descriptive ids with an empty description.

<CodeGroup>
  ```python Python theme={null}
  from krun import Krun

  client = Krun()

  result = client.decide(
      context="I was charged twice for the same order",
      questions={
          "intent": {
              "type": "choice",
              "options": {
                  "transaction_charged_twice": "",
                  "card_arrival": "",
                  "lost_or_stolen_card": "",
              },
          }
      },
  )

  answer = result.answers["intent"]
  print(answer.choice)             # transaction_charged_twice
  print(answer.abstention_status)  # calibrated
  ```

  ```bash curl theme={null}
  curl https://api.krun.ai/v1/decide \
    -H "Authorization: Bearer $KRUN_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "context": "I was charged twice for the same order",
      "questions": {
        "intent": {
          "type": "choice",
          "options": {
            "transaction_charged_twice": "",
            "card_arrival": "",
            "lost_or_stolen_card": ""
          }
        }
      }
    }'
  ```
</CodeGroup>

```json Response theme={null}
{
  "model": "krun-one-v0",
  "answers": {
    "intent": {
      "type": "choice",
      "choice": "transaction_charged_twice",
      "confidence": 0.999693,
      "probabilities": {
        "transaction_charged_twice": 0.999799,
        "card_arrival": 0.000106,
        "lost_or_stolen_card": 0.000095
      },
      "abstain": false,
      "abstention_status": "calibrated"
    }
  },
  "usage": { "input_tokens": 40 }
}
```

With label-only options, `abstention_status` is `calibrated`: the abstention threshold was validated for this setup. See [Abstention](/concepts/abstention#calibrated).

## Out-of-scope messages

When a message matches none of your intents, the model abstains. With the same options and the context `"What is the weather like on Mars?"`:

```json theme={null}
{
  "choice": null,
  "confidence": 0.009176,
  "probabilities": {
    "transaction_charged_twice": 0.330275,
    "card_arrival": 0.330275,
    "lost_or_stolen_card": 0.339451
  },
  "abstain": true,
  "abstention_status": "calibrated"
}
```

Route these messages to a fallback, like a general assistant or a human, instead of forcing them into an intent.

## Naming intents

With label-only options, the option id is all the model sees about the intent. Good ids make a difference:

* Use descriptive `snake_case` ids: `lost_or_stolen_card`, not `intent_07`.
* Keep ids distinct. If two intents are hard to tell apart from their names, expect more abstentions between them.
* Avoid a catch-all like `other`. Let abstention handle out-of-scope messages.

## Intents with descriptions

You can add a description to each option when an id alone is ambiguous:

```json theme={null}
"options": {
  "shipping": "Shipping and delivery issues",
  "returns": "Returns and refunds",
  "billing": "Billing and payment issues"
}
```

This works well for accuracy, but abstention for intents with descriptions is `advisory`, not `calibrated`. Treat `abstain` as a hint and keep your own checks for high-stakes routes.

## Many intents

A question can have up to 64 options. If you have more intents, route in two steps: first choose a category, then choose an intent within that category in a second request.
