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 · 150 lines markdown
Rendered Raw Blame History
1# Gemini — Function calling (`tools[].functionDeclarations`)23**Status:** DOCUMENTED + LIVE_VERIFIED (2026-09-18 run — see "Live verification" section at the end)45Sources:6- https://ai.google.dev/gemini-api/docs/generate-content/function-calling (generateContent flavour) · https://ai.google.dev/gemini-api/docs/function-calling (Interactions flavour)7- https://ai.google.dev/gemini-api/docs/generate-content/thought-signatures · https://ai.google.dev/gemini-api/docs/thinking#signatures8- https://ai.google.dev/gemini-api/docs/tool-combination · https://ai.google.dev/gemini-api/docs/live-tools · https://ai.google.dev/api/live9- https://ai.google.dev/api/generate-content (#Tool #FunctionDeclaration #FunctionCallingConfig #FunctionCall #FunctionResponse #FunctionResponsePart #Behavior #Scheduling)10- SDK: https://github.com/googleapis/python-genai (README: AFC, MCP) · https://github.com/googleapis/js-genai1112Last verified: 2026-09-18 (docs only)1314## 1. Flow15161. Declare functions in `tools[].functionDeclarations[]`.172. Model answers with `functionCall` parts `{name, args, id}` — **Gemini 3 always returns an `id`**; the first `functionCall` of each step carries a `thoughtSignature`.183. You execute the function(s) and append a content (role `user` — the reference also mentions role `function`) with `functionResponse` parts `{name, response, id}`.194. Model produces text or further calls (compositional). Repeat.2021Check `candidates[].finishReason`: `STOP`, `MALFORMED_FUNCTION_CALL`, `UNEXPECTED_TOOL_CALL` (tool called but none enabled), `TOO_MANY_TOOL_CALLS`, `MISSING_THOUGHT_SIGNATURE`.2223## 2. Declaration fields (`FunctionDeclaration`)2425| Field | Type | Required | Notes |26|---|---|---|---|27| `name` | string | yes | `[A-Za-z0-9_.:-]`, ≤128 chars; SDK: must start with letter/underscore; guide: no spaces/periods/dashes |28| `description` | string | yes (REST ref) | Drives tool selection — be specific |29| `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` |30| `parametersJsonSchema` | JSON Schema | no | Full JSON Schema object (`additionalProperties`, etc.). Mutually exclusive with `parameters` |31| `response` / `responseJsonSchema` | Schema / JSON Schema | no | Return-type description; mutually exclusive pair |32| `behavior` | `UNSPECIFIED` \| `BLOCKING` \| `NON_BLOCKING` | no | **Live API only**; default BLOCKING |3334Max 512 declarations per request (SDK docstring). Best practice: 10–20 active tools; low temperature; strong typing/enums; validate high-impact calls with the user.3536## 3. Modes (`toolConfig.functionCallingConfig`)3738| `mode` | Behaviour | `allowedFunctionNames` |39|---|---|---|40| `AUTO` (default when only function declarations) | call or natural-language reply | ignored |41| `ANY` | always a function call, schema-constrained; large/deep schemas may be rejected | restricts choice |42| `NONE` | never call (same as sending no declarations) | — |43| `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 |44| `MODE_UNSPECIFIED` | do not use | |4546Interactions API twin: `generation_config.tool_choice: "auto"|"any"|"none"|"validated"` or `{"allowed_tools":{"mode":"any","tools":[...]}}`.4748## 4. Parallel and compositional calls4950| | Parallel | Compositional (sequential) |51|---|---|---|52| Shape | several `functionCall` parts in one model content | one call per step, chained across turns |53| Signatures (Gemini 3) | only the **first** `functionCall` part carries `thoughtSignature` | each step's first call carries one; all must be returned |54| 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 |5556Supported 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 ✔).5758## 5. Thought signatures (mandatory on Gemini 3)5960| Rule | Detail |61|---|---|62| 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 |63| 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`" |64| Non-FC parts | echo recommended, not validated |65| Don'ts | don't merge a signed part with an unsigned one; don't combine two signed parts; don't interleave parallel FC/FR |66| Injected history | dummy signatures `"skip_thought_signature_validator"` or `"context_engineering_is_the_way_to_go"` skip validation |67| Streaming | with no FC, the signature may arrive in an empty-text part — read until `finishReason` |68| SDKs | handled automatically when you append the full response content to history |69| OpenAI compat | signatures travel in `extra_content` (see thought-signatures guide) |7071## 6. Function responses7273| Field | Notes |74|---|---|75| `name` | required |76| `response` | required JSON object (any keys: `output`, `result`, `error`…) |77| `id` | echo `functionCall.id` (mandatory mapping on Gemini 3) |78| `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>"}` |79| `scheduling` | Live NON_BLOCKING only: `SILENT` \| `WHEN_IDLE` (default) \| `INTERRUPT` |80| `willContinue` | Live NON_BLOCKING only: generator-style multiple responses; `false` + empty response ends the call (add `scheduling: SILENT` to avoid triggering generation) |8182## 7. Live API (BidiGenerateContent)8384- 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.85- `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`.86- Only `googleSearch` can be combined with function declarations in Live.8788## 8. Multi-tool (built-in + custom) — Gemini 3, Preview8990Set `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](index.md#4-multi-tool-combination-rules).9192## 9. SDK conveniences9394| Feature | Python `google-genai` | JS `@google/genai` |95|---|---|---|96| 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|bool|str|list|pydantic.BaseModel` (no dicts). Docstring becomes the whole description | AFC for `mcpToTool()` tools; `automaticFunctionCalling: {disable: true}` to opt out |97| MCP | `tools=[ClientSession]` (experimental) | `tools: [mcpToTool(client)]` (experimental) — see [mcp.md](mcp.md) |98| README warning | AFC will move from `Models.generate_content` to `Chats` in the next major version | same |99100## 10. Minimal examples101102```bash103curl -s "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.5-flash-lite:generateContent" \104  -H "x-goog-api-key: $GEMINI_API_KEY" -H "Content-Type: application/json" \105  -d '{"contents":[{"role":"user","parts":[{"text":"Weather in Paris?"}]}],106       "tools":[{"functionDeclarations":[{"name":"get_weather","description":"Weather for a city.",107         "parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}]}],108       "toolConfig":{"functionCallingConfig":{"mode":"ANY","allowedFunctionNames":["get_weather"]}}}'109```110111```python112from google import genai113from google.genai import types114client = genai.Client()  # GEMINI_API_KEY115decl = types.FunctionDeclaration(name="get_weather", description="Weather for a city.",116        parameters_json_schema={"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]})117r = client.models.generate_content(model="gemini-3.5-flash-lite", contents="Weather in Paris?",118        config=types.GenerateContentConfig(tools=[types.Tool(function_declarations=[decl])]))119fc = r.candidates[0].content.parts[0]120# echo the model part (with thought_signature) then reply:121follow = client.models.generate_content(model="gemini-3.5-flash-lite", contents=[122    types.Content(role="user", parts=[types.Part(text="Weather in Paris?")]),123    r.candidates[0].content,124    types.Content(role="user", parts=[types.Part(function_response=types.FunctionResponse(125        name=fc.function_call.name, id=fc.function_call.id, response={"temp_c": 18}))])],126    config=types.GenerateContentConfig(tools=[types.Tool(function_declarations=[decl])]))127```128129```ts130import { GoogleGenAI } from '@google/genai';131const ai = new GoogleGenAI({});132const r = await ai.models.generateContent({ model: 'gemini-3.5-flash-lite', contents: 'Weather in Paris?',133  config: { tools: [{ functionDeclarations: [{ name: 'get_weather', description: 'Weather for a city.',134    parametersJsonSchema: { type: 'object', properties: { city: { type: 'string' } }, required: ['city'] } }] }] } });135console.log(r.functionCalls);136```137138## Live verification (2026-09-18)139`gemini-3.5-flash-lite`, raws `tmp-live/gemini-tools/a*.json` (all HTTP 200 unless stated):140141- **Forced call** (`toolConfig.functionCallingConfig.mode: ANY` + `allowedFunctionNames`) → one part `{functionCall:{name:"get_weather", args:{city:"Paris"}, id:"call_356059"}, thoughtSignature:"…"}`, `finishReason: STOP`.142- **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`.143- **Parallel**: two declarations, mode ANY → parts `[functionCall+thoughtSignature, functionCall]` (`call_243490`, `call_243491`) — only the first carries a signature, exactly as the docs describe.144- **`parametersJsonSchema`** (plain JSON Schema with an enum) → `args {city:"Rome", unit:"C"}`.145- **`mode: NONE`** → text only; **`mode: VALIDATED`** → accepted (functionCall returned).146- **`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.147- 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`.148149Examples: `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`.150