extractToolCalls static method

List<FunctionCallResponse> extractToolCalls(
  1. String jsonStr
)

Extract all function calls from an SDK response JSON string.

Accepts the structural variants observed in the wild:

  1. Top-level tool_calls list (Gemma 4 standard path).
  2. content array entries with type: "tool_call" (multimodal).
  3. Concatenated multi-document JSON — when the model emits two or more <|tool_call>...<tool_call|> blocks, the SDK serializes them as separate {role:assistant,tool_calls:[...]}{role:assistant,tool_calls:[...]} documents back-to-back rather than wrapping them in an array. We split on top-level }{ boundaries and parse each fragment.

Each call element may be either OpenAI-style ({type: "function", function: {name, arguments}}) or flat ({name, arguments}) — both accepted.

String values inside arguments (and nested maps/lists) are stripped of the <|"|> Gemma 4 escape token, which leaks through SDK parsing.

Implementation

static List<FunctionCallResponse> extractToolCalls(String jsonStr) {
  final result = <FunctionCallResponse>[];
  for (final fragment in _splitConcatenatedJson(jsonStr)) {
    final Map<String, dynamic> json;
    try {
      final parsed = jsonDecode(fragment);
      if (parsed is! Map<String, dynamic>) continue;
      json = parsed;
    } on FormatException {
      continue;
    }
    _harvestCalls(json, result);
  }
  // Raw Gemma 4 `<|tool_call>call:NAME{...}<tool_call|>` tokens, when the
  // structured pass found nothing. `@litert-lm/core` 0.12.1 and 0.14.0 left
  // every web call as text (verified with Gemma 4 E4B); from 0.18.0 the web
  // runtime, like native, converts a complete call itself, so this reads a
  // block the runtime did not convert (cut off or malformed) and history
  // text that carries the tokens.
  if (result.isEmpty && jsonStr.contains(_rawToolCallOpen)) {
    result.addAll(_rawTokenCalls(_responseText(jsonStr)));
  }
  // FunctionGemma, same reason: when its call comes back as text rather than
  // `tool_calls` — the web SDK, or a `.litertlm` exported without the
  // function_gemma model type, whose runtime creates no tool-call channel —
  // parse the wire format the model wrote.
  if (result.isEmpty && jsonStr.contains(functionGemmaStartCall)) {
    result.addAll(FunctionGemmaCallFormat().parseAll(_responseText(jsonStr)));
  }
  return result;
}