# Gemma 4 tool-calling format (token-delimited `call:NAME{…}`) Tool-calling convention of Google's **Gemma 4** open-weights family (`google/gemma-4-*-it`). It is a clean break from the prompt-engineered Pythonic `tool_code` form used by Gemma 3 and hosted Gemini (see `gemini.md`): Gemma 4 introduces **dedicated special tokens** and a compact **token-delimited brace syntax**. Tool declarations, calls, and responses each get their own paired markers, and every string value is wrapped in a `<|"|>` token rather than ASCII quotes. The model emits one call as `<|tool_call>call:NAME{key:value,…}`; the developer parses it, runs the tool, and appends `<|tool_response>response:NAME{…}`. Verified against: the official "Function calling with Gemma 4" guide (`ai.google.dev/gemma/docs/capabilities/text/function-calling-gemma4`), including the byte-exact `processor.apply_chat_template(...)` renderings and the reference `extract_tool_calls` regex it ships. All example streams below are copied from that page (model `google/gemma-4-E2B-it`). ## Special tokens Gemma 4 wraps each structural element in a paired token. Note the **asymmetric pipe placement** — an opener carries the pipe on the left (`<|x>`) and its closer carries it on the right (``): | Open | Close | Purpose | |---|---|---| | `` | — | Beginning of sequence | | `<|turn>` | `` | One conversation turn; the role name is the first line of the body | | `<|tool>` | `` | A tool **declaration** block (in the system turn) | | `<|tool_call>` | `` | One tool **call** emitted by the model | | `<|tool_response>` | `` | One tool **result** fed back to the model | | `<|think|>` | — | Thinking-mode enable flag, injected in the system turn | | `<|channel>` | `` | Reasoning channel; `<|channel>thought` opens the model's chain-of-thought (closed by ``) before the visible reply | | `<|"|>` | `<|"|>` | String-literal delimiter (same token on both ends) | | `` | — | End of sequence | Because the string delimiter is a token (`<|"|>`), values may contain raw ASCII quotes and commas without escaping — only a literal `<|"|>` token sequence cannot appear inside a string. Thinking variants emit reasoning in a dedicated channel — `<|channel>thought\n…\n` at the start of the model turn, before the reply (`enable_thinking` injects a `<|think|>` flag into the system turn). Prior-turn thoughts are stripped from history except on a tool-calling turn, where they are preserved between the call and its response. ## Roles / turn structure Each turn is `<|turn>{role}\n{body}`. Roles are `system`, `user`, `model`. With a generation prompt the stream ends at `<|turn>model\n` and the model continues. Tool declarations are merged into the `system` turn; tool calls and the following tool responses are emitted inside the `model` turn (the response block immediately follows the call block in the re-rendered history). ## Tool definitions Each tool is declared in the system turn as `<|tool>declaration:NAME{…}`, where the body is the schema serialized in the same brace syntax used by calls. Types are upper-cased strings (`STRING`, `OBJECT`, …). Byte-exact, from the guide: ```text <|tool>declaration:get_current_temperature{description:<|"|>Gets the current temperature for a given location.<|"|>,parameters:{properties:{location:{description:<|"|>The city name, e.g. San Francisco<|"|>,type:<|"|>STRING<|"|>} },required:[<|"|>location<|"|>],type:<|"|>OBJECT<|"|>} } ``` ## Tool-call format The model emits one call per `<|tool_call>…` block. The body is `call:NAME{ARGS}`, where `ARGS` is a comma-separated list of `key:value` pairs: ```text <|tool_call>call:get_current_temperature{location:<|"|>London<|"|>} ``` Value grammar inside `{…}`: | Value kind | Encoding | Example | |---|---|---| | string | `<|"|>text<|"|>` | `location:<|"|>London<|"|>` | | int / float | bare | `count:42` | | bool | bare | `flag:true` | | null | bare | `unit:null` | | list | `[v,v,…]` | `tags:[<|"|>a<|"|>,<|"|>b<|"|>]` | | nested object | `{k:v,…}` | `config:{theme:<|"|>dark<|"|>}` | The reference parser shipped in the guide: ```python [{ "name": name, "arguments": { k: cast((v1 or v2).strip()) for k, v1, v2 in re.findall(r'(\w+):(?:<\|"\|>(.*?)<\|"\|>|([^,}]*))', args) } } for name, args in re.findall(r"<\|tool_call>call:(\w+)\{(.*?)\}", text, re.DOTALL)] ``` i.e. each argument value is either a `<|"|>…<|"|>` string or a bare run of non-`,}` characters (cast to int/float/bool, else kept as a string). ## Multiple / parallel tool calls Parallel calls are consecutive `<|tool_call>…` blocks (one call each), returned in order. The application returns one `<|tool_response>` per call in the same order. ## Tool-result format Each result is `<|tool_response>response:NAME{…}`, the response object serialized in the same brace syntax. Byte-exact, from the guide's re-rendered history: ```text <|tool_response>response:get_current_weather{temperature:15,weather:<|"|>sunny<|"|>} ``` ## End-to-end example Byte-exact `apply_chat_template` output from the guide (system + tool, user, model call, tool response, final answer — note the response block sits in the same model turn, right after the call): ```text <|turn>system You are a helpful assistant.<|tool>declaration:get_current_weather{description:<|"|>Gets the current weather in a given location.<|"|>,parameters:{properties:{location:{description:<|"|>The city and state, e.g. "San Francisco, CA" or "Tokyo, JP"<|"|>,type:<|"|>STRING<|"|>},unit:{description:<|"|>The unit to return the temperature in.<|"|>,enum:[<|"|>celsius<|"|>,<|"|>fahrenheit<|"|>],type:<|"|>STRING<|"|>} },required:[<|"|>location<|"|>],type:<|"|>OBJECT<|"|>} } <|turn>user Hey, what's the weather in Tokyo right now? <|turn>model <|tool_call>call:get_current_weather{location:<|"|>Tokyo, JP<|"|>}<|tool_response>response:get_current_weather{temperature:15,weather:<|"|>sunny<|"|>}The current weather in Tokyo is 15 degrees Celsius and sunny. ``` ## Parsing notes & gotchas - **String delimiter is a token, not a quote.** Inside `<|"|>…<|"|>` the bytes `"` and `,` are literal data — the example `<|"|>The city and state, e.g. "San Francisco, CA"…<|"|>` contains both. Split arguments on `,`/`}` only **outside** a `<|"|>…<|"|>` span. - **Asymmetric pipes.** The closer is ``, not `` or `<|tool_call>`. Matching the wrong pipe side will never close the block. - **One call per block.** Unlike a JSON `tool_calls[]` array, parallelism is "more blocks", not "more entries in one block". - **Bare scalars.** A value not wrapped in `<|"|>` is `true`/`false` → bool, `null`/`none` → null, numeric → number, otherwise a bare string (e.g. an unquoted enum or type name like `STRING`). - **Not Gemma 3 / hosted Gemini.** Those use the Pythonic `tool_code` / `default_api` form in `gemini.md`. Gemma 4 replaced it with this token syntax; the two are not interchangeable. ## Sources - Function calling with Gemma 4 (byte-exact chat-template renderings + reference parser): https://ai.google.dev/gemma/docs/capabilities/text/function-calling-gemma4 - Gemma 4 prompt formatting: https://ai.google.dev/gemma/docs/core/prompt-formatting-gemma4