allowedNames function
The names detection may produce once choice has had its say.
A choice does not only demand calls, it NARROWS them: a caller that pinned one function has not authorised any other. Gating detection on this instead of the raw declared list is what turns ToolChoice from a hint the prompt makes into a contract the parser keeps — without it, a model that ignores a pinned choice and calls a different declared function produces a call that validates cleanly and runs the wrong thing.
Implementation
Set<String> allowedNames(List<FunctionTool> functions, ToolChoice choice) {
final names = {for (final f in functions) f.name};
return switch (choice) {
NamedToolChoice(:final name) => names.intersection({name}),
_ => names,
};
}