toolCallsOf function

List<FunctionCallResponse> toolCallsOf(
  1. Message message
)

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 response InferenceChat stored (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 it reads with none; its Message.toolCalls keep the arguments. 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));
}