Decide
decide() returns a typed decision for one call. Chat completions stay chat completions. Pass using to say which of the three you want. The response repeats using and model.
The three choices
| using | You also pass | What runs |
|---|---|---|
| sava | nothing else | Tokand's hosted Sava model, on Tokand's routing |
| your-model | model: "gpt-4.1" | A typed decision on your model |
| tokand-model | model: "tokand/…" | The same kind of decision, on that Tokand router model. Not Sava. |
Calls
const ai = withTokand(openai, { apiKey: process.env.TOKAND_KEY })
await ai.decide({
using: "sava",
state: { messages },
questions,
})
await ai.decide({
using: "your-model",
model: "gpt-4.1",
tier: "measured",
state: { messages },
questions,
})
await ai.decide({
using: "tokand-model",
model: "tokand/qwen",
state: { messages },
questions,
})What comes back
level is L0 unless you set it to L1, L2, or auto.
{
"using": "your-model",
"model": "gpt-4.1",
"level": "L0",
"tier": "measured",
"tokey": { "tokens": { "raw_in": 840, "filtered_in": 210 } },
"decisions": []
}Token saver
Omit tier and the state is sent unchanged. Set it to shrink state.messages before the decision runs. The tiers are the same as chat: safe, measured, aggressive, and aggressive+. Questions are not shrunk. The response repeats tier.
await ai.decide({
using: "your-model",
model: "gpt-4.1",
tier: "measured",
state: { messages },
questions,
})When it fails
decide() does not fall through to chat.completions.create. If the choice you named cannot run, the call throws DecideError with the same using and model. Sava rejects a model id. your-model rejects a tokand/ id. tokand-model requires one.