Skip to content

Capabilities

Function Calling

Custom (client-side) tools — definitions, parallel calls, tool choice

Read this when
  • Defining tools for a feature
  • Wiring tool calls in a new provider adapter

Tools are declared via ai.ToolInfo (name, description, JSON schema, optional Parallel flag). Each provider adapter converts ToolInfo to its native function-call format. Tool results return as ai.RoleToolResult messages carrying ToolCallID, ToolName, and an IsError flag.

For provider-hosted tools (web search, code execution, computer use, etc.), see server-tools.md.

Tool Declarations

ProviderAPIpi-goNotes
Anthropictools array; strict-by-defaultToolParam (convert.go:169-208)
OpenAI Chattools array with strict modeChatCompletionToolParam (convert.go:190-214); strict gated by compat flag
OpenAI Responsestools arrayFunctionToolParam (convert.go:208-231)
Google Geminitools[].functionDeclarations
Claude CLI❌ (CLI manages its own tools)Tools ignored (claude.go:124)

Parallel Tool Calls

ProviderAPIpi-goNotes
Anthropic✅ multiple tool_use blocks per response; disable_parallel_tool_use flag⚠️streaming accumulates blocks; flag not forwarded
OpenAI Chatparallel_tool_calls: true (default)⚠️deltas accumulated by index (openai.go:150-193); flag not exposed
OpenAI Responses✅ multiple output itemstracked by index (openairesponses.go:158)
Google Gemini✅ multiple functionCall parts⚠️parts iterated; no flag
Claude CLI

Tool Result Content

ai.ToolResult carries text, an image, or media. ToolResult.Contents renders it into message blocks: text becomes ai.Text, an image becomes ai.Image, and media becomes the extracted ai.Text plus the raw ai.File. Injected blocks in ToolResult.Extra, such as ai.Reminder, follow.

ProviderTextImageFileNotes
Anthropictool_result content takes text, image, and document blocks
OpenAI Chat⚠️⚠️a tool message takes text only, so media follows in a user message after the tool-result group
OpenAI Responsesfunction_call_output takes a content list of input_text, input_image, and input_file
Google GeminifunctionResponse.response is a JSON object with no binary part

An ai.Reminder block reaches every provider as plain text, in the same place the text of the tool goes. The Injected and Origin fields never reach the wire: they route the message, and routing is not content.

Tool Choice

ai.ToolChoice supports auto (default), none, required, or a specific tool name.

Providerautononerequired / anyspecificpi-go
Anthropicany✅ all four (convert.go:215-231)
OpenAI Chatrequired✅ all four (convert.go:222-241)
OpenAI Responses✅ all four (convert.go:238-261)
Google Gemini✅ AUTO✅ NONE✅ ANY⚠️ via allowedFunctionNames⚠️

Provider Documentation

pi-go Gaps

  • Strict schema mode plumbed only on OpenAI Chat via compat flag (convert.go:205-206); not exposed as ToolInfo field, not passed to other providers.
  • OutputSchema (tool.go) defined on ToolInfo but not forwarded by any provider.
  • ToolInfo.Parallel flag exists but is not forwarded; disable_parallel_tool_use (Anthropic) / parallel_tool_calls: false (OpenAI) cannot be set.
  • Specific-tool forcing on Gemini uses allowedFunctionNames (a list, in ANY mode); pi-go’s single-string ToolChoice doesn’t map cleanly.
  • Claude CLI drops all tool definitions silently.
  • Image tool results on Gemini are dropped. The function-response schema has no place for binary data. This adapter also does not send a follow-up user message, as the OpenAI Chat adapter does.