mixle.task.constrained module

Grammar-constrained plan decoding – invalid output becomes impossible, not just detected.

sft_plan generates freely and then gates (parse + specs + copy-fidelity). This module moves the gate INTO the decoder: a character-level automaton over the plan grammar masks the LM’s logits at every step, so the model can only ever choose among characters that keep the output a valid plan – tool names come from the specs, argument keys from the chosen tool, and argument VALUES are anchored to the request text (each value character must extend a live substring match), which makes the silent copy error (order 4242 -> order_id=4202) unrepresentable: after 42 the only continuation the request offers is 4.

The practical payoff is largest for small or undertrained models: instead of having to place all its probability mass on exactly the right free-form string, the LM only ranks the handful of legal continuations – so constrained decoding lifts agreement precisely where compute is scarce.

class PlanGrammar(specs, request)[source]

Bases: object

The character automaton: allowed(state) and advance(state, char) over the plan DSL.

Parameters:
start()[source]
Return type:

_State

allowed(s)[source]
Parameters:

s (_State)

Return type:

set[str]

advance(s, c)[source]
Parameters:
  • s (_State)

  • c (str)

Return type:

_State

constrained_plan_decode(lm, codec, request, specs, *, max_new=200)[source]

Greedy decode with the grammar mask: the highest-logit LEGAL character at every step.

Returns (plan_text, confidence) — the confidence is the mean full-vocabulary log-probability the model itself put on the legal path it took — or None when the automaton dead-ends. The grammar guarantees FORM; a well-formed wrong plan is still possible from a weak model, so callers gate emission on a calibrated confidence floor (see sft_planner).

Parameters:
Return type:

tuple[str, float] | None