fix(decision): take a distribution-less answer as a committed choice

Merged
OK
13d ago
+73-12
  • AI Gateway reruns an uncertain decision on a fallback model when providerOptions.gateway.models carries a when: { confidenceBelow } entry (Vercel changelog, 2026-10-06). The executor already forwards providerOptions untouched, so a decision-model fallback worked by accident.
  • A language-model fallback returns { type: 'choice', choice } with no probabilities and no confidence. selected() in packages/decision/src/decide.ts threw MODEL_OUTPUT_INVALID on it, so the escalated step died.
  • A distribution-less answer now reads as a committed choice: probability 1, confidence 0. minProbability lets it through, minConfidence blocks it, matching the documented "0 when the provider reports none". Score answers get the same treatment.
  • Docs show the gateway fallback on the executor and name the gate interaction.
providerOptions: {
  gateway: { models: [{ model: 'openai/gpt-6-luna-decisions', when: { confidenceBelow: 0.6 } }] },
},

Verified

Ran it locally: yes

  • Live AI Gateway, Jev primary, confidenceBelow: 0.99 to force the fallback, one choice and one score question, through the package's own decide().
fallbackmainthis branch
openai/gpt-5-nano (language model)MODEL_OUTPUT_INVALID The decision model returned an answer without a choice distribution.intent {choice:"billing", probability:1, confidence:0}, quality {choice:"2", probability:1, score:2, confidence:0}
openai/gpt-6-luna-decisions (decision model)intent {choice:"billing", probability:0.89, confidence:0.83}unchanged
  • With the threshold below Jev's confidence the gateway returns the primary result unchanged and nothing in the executor differs from main.
  • tests/cli.test.ts fails on this branch and on HEAD alike with CONFIG_LOAD_FAILED, unrelated to this change.