symfonic.capabilities.tools.stages.forced¶
forced ¶
Forced-choice stage — resolve (and release) the mandatory tool.
This stage answers which tool is forced. It deliberately does not narrow the candidate set: keeping the force alive through later stages is the pipeline's protection rule, which is what makes "force wins over the palette" a property of the composition rather than a special case buried in one consumer.
ForcedChoiceStage ¶
ForcedChoiceStage(*, resolver: Any = None, state_key: str = 'forced_tool_choice', is_tool_message: Callable[[Any], bool] = _default_is_tool_message)
Resolve the forced tool_choice for this iteration.
Precedence, unchanged from v7.10:
- an explicit
state["forced_tool_choice"]stamp — tests and adopters pre-stamp directly; - the registered resolver, which re-runs every iteration so force and release are symmetric by construction;
None— let the model choose, the safe default.
The release check runs on both paths: once a ToolMessage naming
the forced tool is in history the force is spent. A resolver that
raises releases too, because a stalled loop is worse than an
unforced turn.