toolCallsOf function
The calls a MessageType.toolCall message carries, for an engine that replays a history.
Message.toolCalls when the message has them. Otherwise Message.text is parsed, so a history saved before those fields existed still replays. The text has had these shapes:
{"tool_calls": [...]}— the canonical form, and the raw LiteRT-LM responseInferenceChatstored (also several such objects back to back);{"name": ..., "parameters": {...}}or a JSON list of them — the genai and Genkit converters;- the model's own words — native Gemma 4 or FunctionGemma tokens, or a JSON, Qwen, DeepSeek, Phi or Llama function-call block.
Each call may be OpenAI-style ({"function": {"name", "arguments"}}) or
flat, with its arguments under arguments, parameters or args, as an
object or a JSON string; missing or blank arguments are {}. An id is
kept. One JSON document of calls is read whole: when one of its calls
cannot be read (arguments that are not an object), none is returned, so a
replay does not answer part of that turn. The model-format fallbacks read
call by call. Returns an empty list for any other message type or when
nothing parses, a toolCall message included: the engine then replays its
Message.text. A web Gemma 4 call recorded as text has lost the escape
tokens that mark its string arguments, so from text alone its strings read
as bare values: digits come back as a number, and a string holding a comma
or a bracket refuses the call or comes back cut short. Its
Message.toolCalls keep the arguments as the model wrote them. One model
turn may be several consecutive toolCall messages; an engine that replays
calls merges them.
Implementation
List<FunctionCallResponse> toolCallsOf(Message message) {
if (message.type != MessageType.toolCall) return const [];
if (message.toolCalls.isNotEmpty) return message.toolCalls;
return List.unmodifiable(_parseToolCallText(message.text));
}