SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
13 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
12.2 KB

# Gemini — Function calling (tools[].functionDeclarations)

Status: DOCUMENTED + LIVE_VERIFIED (2026-09-18 run — see "Live verification" section at the end)

Sources:

Last verified: 2026-09-18 (docs only)

# 1. Flow

  1. Declare functions in tools[].functionDeclarations[].
  2. Model answers with functionCall parts {name, args, id} — Gemini 3 always returns an id; the first functionCall of each step carries a thoughtSignature.
  3. You execute the function(s) and append a content (role user — the reference also mentions role function) with functionResponse parts {name, response, id}.
  4. Model produces text or further calls (compositional). Repeat.

Check candidates[].finishReason: STOP, MALFORMED_FUNCTION_CALL, UNEXPECTED_TOOL_CALL (tool called but none enabled), TOO_MANY_TOOL_CALLS, MISSING_THOUGHT_SIGNATURE.

# 2. Declaration fields (FunctionDeclaration)

Field Type Required Notes
name string yes [A-Za-z0-9_.:-], ≤128 chars; SDK: must start with letter/underscore; guide: no spaces/periods/dashes
description string yes (REST ref) Drives tool selection — be specific
parameters Schema no OpenAPI 3.03 subset: type, properties, required, enum, description, items, format, nullable, anyOf, propertyOrdering, minimum/maximum, minItems/maxItems, minLength/maxLength, pattern, default, example, title, minProperties/maxProperties. Type names may be upper-case (OBJECT, STRING). Param names ≤64 chars. Mutually exclusive with parametersJsonSchema
parametersJsonSchema JSON Schema no Full JSON Schema object (additionalProperties, etc.). Mutually exclusive with parameters
response / responseJsonSchema Schema / JSON Schema no Return-type description; mutually exclusive pair
behavior UNSPECIFIED | BLOCKING | NON_BLOCKING no Live API only; default BLOCKING

Max 512 declarations per request (SDK docstring). Best practice: 10–20 active tools; low temperature; strong typing/enums; validate high-impact calls with the user.

# 3. Modes (toolConfig.functionCallingConfig)

mode Behaviour allowedFunctionNames
AUTO (default when only function declarations) call or natural-language reply ignored
ANY always a function call, schema-constrained; large/deep schemas may be rejected restricts choice
NONE never call (same as sending no declarations) —
VALIDATED call or text, calls schema-validated by constrained decoding; default and only allowed mode when built-in tools or structured outputs are combined / includeServerSideToolInvocations=true restricts choice
MODE_UNSPECIFIED do not use

Interactions API twin: generation_config.tool_choice: "auto"|"any"|"none"|"validated" or {"allowed_tools":{"mode":"any","tools":[...]}}.

# 4. Parallel and compositional calls

Parallel Compositional (sequential)
Shape several functionCall parts in one model content one call per step, chained across turns
Signatures (Gemini 3) only the first functionCall part carries thoughtSignature each step's first call carries one; all must be returned
Reply all functionResponse parts in one user content, after all calls; order may differ (matched by id/name); interleaving FC1,FR1,FC2,FR2 → 400 one response per step

Supported per the guide table: Gemini 3.8/3.7/3.6/3.5 Flash, 3.5 Flash-Lite, 3.1 Pro Preview, 3.1 Flash-Lite, 2.5 Pro/Flash/Flash-Lite (function, parallel and compositional all ✔).

# 5. Thought signatures (mandatory on Gemini 3)

Rule Detail
Where Part.thoughtSignature (base64) on the first functionCall of each step; on the last part when no call (Gemini 3); Gemini 2.5: on the first part of any type, optional to return
Must echo Gemini 3: yes for the current turn (API walks back to the last user content with standard text; every step after it is validated) → HTTP 400 "Function call X in the N. content block is missing a thought_signature"
Non-FC parts echo recommended, not validated
Don'ts don't merge a signed part with an unsigned one; don't combine two signed parts; don't interleave parallel FC/FR
Injected history dummy signatures "skip_thought_signature_validator" or "context_engineering_is_the_way_to_go" skip validation
Streaming with no FC, the signature may arrive in an empty-text part — read until finishReason
SDKs handled automatically when you append the full response content to history
OpenAI compat signatures travel in extra_content (see thought-signatures guide)

# 6. Function responses

Field Notes
name required
response required JSON object (any keys: output, result, error…)
id echo functionCall.id (mandatory mapping on Gemini 3)
parts[] FunctionResponsePart{inlineData{mimeType,data}} — multimodal responses (Gemini 3): image/png, image/jpeg, image/webp, application/pdf, text/plain; reference from response with {"$ref": "<inlineData.display_name>"}
scheduling Live NON_BLOCKING only: SILENT | WHEN_IDLE (default) | INTERRUPT
willContinue Live NON_BLOCKING only: generator-style multiple responses; false + empty response ends the call (add scheduling: SILENT to avoid triggering generation)

# 7. Live API (BidiGenerateContent)

  • Declare tools in setup.tools; server sends toolCall {functionCalls[{id,name,args}]} and may send toolCallCancellation {ids[]} on interruption; client answers toolResponse {functionResponses[]} (session.send_tool_response). No automatic tool handling.
  • behavior: NON_BLOCKING = asynchronous calling: default on gemini-3.8-live (BLOCKING still allowed), only mode on gemini-3.8-live-extended-thinking (BLOCKING = hard error, scheduling unsupported), unsupported on gemini-3.1-flash-live-preview (sync only), sync + async on gemini-2.5-flash-native-audio-preview-12-2025.
  • Only googleSearch can be combined with function declarations in Live.

# 8. Multi-tool (built-in + custom) — Gemini 3, Preview

Set toolConfig.includeServerSideToolInvocations: true; response contains toolCall/toolResponse (server tools), executableCode/codeExecutionResult (code execution) and functionCall parts, each with id and thoughtSignature. Echo every part unchanged, then append your functionResponse. Mode is VALIDATED. See index.md §4.

# 9. SDK conveniences

Feature Python google-genai JS @google/genai
Automatic function calling (AFC) pass Python callables in config.tools; SDK declares (FunctionDeclaration.from_callable), executes, loops (automatic_function_calling.maximum_remote_calls default 10, disable, ignore_call_history; history in response.automatic_function_calling_history). Allowed param types: `int float
MCP tools=[ClientSession] (experimental) tools: [mcpToTool(client)] (experimental) — see mcp.md
README warning AFC will move from Models.generate_content to Chats in the next major version same

# 10. Minimal examples

bash
curl -s "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.5-flash-lite:generateContent" \
  -H "x-goog-api-key: $GEMINI_API_KEY" -H "Content-Type: application/json" \
  -d '{"contents":[{"role":"user","parts":[{"text":"Weather in Paris?"}]}],
       "tools":[{"functionDeclarations":[{"name":"get_weather","description":"Weather for a city.",
         "parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}]}],
       "toolConfig":{"functionCallingConfig":{"mode":"ANY","allowedFunctionNames":["get_weather"]}}}'
python
from google import genai
from google.genai import types
client = genai.Client()  # GEMINI_API_KEY
decl = types.FunctionDeclaration(name="get_weather", description="Weather for a city.",
        parameters_json_schema={"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]})
r = client.models.generate_content(model="gemini-3.5-flash-lite", contents="Weather in Paris?",
        config=types.GenerateContentConfig(tools=[types.Tool(function_declarations=[decl])]))
fc = r.candidates[0].content.parts[0]
# echo the model part (with thought_signature) then reply:
follow = client.models.generate_content(model="gemini-3.5-flash-lite", contents=[
    types.Content(role="user", parts=[types.Part(text="Weather in Paris?")]),
    r.candidates[0].content,
    types.Content(role="user", parts=[types.Part(function_response=types.FunctionResponse(
        name=fc.function_call.name, id=fc.function_call.id, response={"temp_c": 18}))])],
    config=types.GenerateContentConfig(tools=[types.Tool(function_declarations=[decl])]))
ts
import { GoogleGenAI } from '@google/genai';
const ai = new GoogleGenAI({});
const r = await ai.models.generateContent({ model: 'gemini-3.5-flash-lite', contents: 'Weather in Paris?',
  config: { tools: [{ functionDeclarations: [{ name: 'get_weather', description: 'Weather for a city.',
    parametersJsonSchema: { type: 'object', properties: { city: { type: 'string' } }, required: ['city'] } }] }] } });
console.log(r.functionCalls);

# Live verification (2026-09-18)

gemini-3.5-flash-lite, raws tmp-live/gemini-tools/a*.json (all HTTP 200 unless stated):

  • Forced call (toolConfig.functionCallingConfig.mode: ANY + allowedFunctionNames) → one part {functionCall:{name:"get_weather", args:{city:"Paris"}, id:"call_356059"}, thoughtSignature:"…"}, finishReason: STOP.
  • Round trip: appending the model turn verbatim + {functionResponse:{name, response:{…}}} → text answer. Stripping thoughtSignature → 400 Function call is missing a thought_signature in functionCall parts. This is required for tools to work correctly… function call default_api:get_weather, position 2.
  • Parallel: two declarations, mode ANY → parts [functionCall+thoughtSignature, functionCall] (call_243490, call_243491) — only the first carries a signature, exactly as the docs describe.
  • parametersJsonSchema (plain JSON Schema with an enum) → args {city:"Rome", unit:"C"}.
  • mode: NONE → text only; mode: VALIDATED → accepted (functionCall returned).
  • behavior: NON_BLOCKING in generateContent → 400 FunctionDeclaration.behavior is only supported by the BidiGenerateContent method. In the Live API the same declaration produced toolCall{functionCalls:[{name,args,id:"function-call-11967657623789764093"}]} and the model kept talking (audio) — non-blocking behaviour confirmed; setup.toolConfig is rejected (close 1007), so the mode cannot be forced in Live.
  • Interactions API twin: tools:[{type:"function",…}] + generation_config.tool_choice{allowed_tools{mode:"any", tools:[…]}} → status:"requires_action", step {id:"call_297992", type:"function_call", name, arguments}; top-level tool_choice → 400 Unknown parameter 'tool_choice'; reply with input:[{type:"function_result", name, call_id, result:[{type:"text", text}]}] + previous_interaction_id.

Examples: examples/gemini/tools/function-calling/{function_calling.py,forced_call.sh,function_calling.ts}, examples/shared/tool-loop/gemini_tool_loop.{py,ts} (all executed). Tests: tests/gemini/test_tools.py.