pub fn carries_tools(body: &Value) -> boolExpand description
Whether the request carries a non-empty tools array.
§This identifies an agentic turn, not a tool-emission turn
The distinction matters and was learned the hard way. This answers “could
this turn produce a tool call?”, never “will it?”. VS Code Copilot in
agent mode sends the tools array on essentially every request —
including prose, planning, summarising and thinking turns — so in the
client this was built for, the answer is permanently yes.
Anything keyed on this therefore applies to a whole agentic session, not to the moment a call is emitted. Adjustments hanging off it must be safe for prose, because they will spend most of their time there.
§Why there is no better signal
Every candidate fails. tool_choice is "auto" on every turn. The last
message’s role does not predict what comes next. A history containing prior
tool_calls only says “this is an agentic session”, which is the thing
already known. This is the same wall super::constrain documents for
grammars: you cannot know before decoding whether the model will emit a
call. The only true discriminator is mid-stream marker detection, which is
a different and much larger piece of machinery.
§Deliberately more lenient than the grammar path
constrain needs the complete list of tool names to
build a GBNF alternation, so it rejects a tools array in which any entry
is missing function.name. That strictness is right for originating a
grammar and wrong here: a request with one malformed tool entry is still an
agentic turn.
A tools key that is present but not a non-empty array — null, [], an
object — reads as no tools. tool_choice is not consulted at all: it can
appear without tools (nothing strips it), and on its own it does not make
a turn agentic.