Capabilities
Function Calling
Custom (client-side) tools — definitions, parallel calls, tool choice
- 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
| Provider | API | pi-go | Notes |
|---|---|---|---|
| Anthropic | ✅ tools array; strict-by-default | ✅ | ToolParam (convert.go:169-208) |
| OpenAI Chat | ✅ tools array with strict mode | ✅ | ChatCompletionToolParam (convert.go:190-214); strict gated by compat flag |
| OpenAI Responses | ✅ tools array | ✅ | FunctionToolParam (convert.go:208-231) |
| Google Gemini | ✅ tools[].functionDeclarations | ✅ | |
| Claude CLI | ❌ (CLI manages its own tools) | ❌ | Tools ignored (claude.go:124) |
Parallel Tool Calls
| Provider | API | pi-go | Notes |
|---|---|---|---|
| Anthropic | ✅ multiple tool_use blocks per response; disable_parallel_tool_use flag | ⚠️ | streaming accumulates blocks; flag not forwarded |
| OpenAI Chat | ✅ parallel_tool_calls: true (default) | ⚠️ | deltas accumulated by index (openai.go:150-193); flag not exposed |
| OpenAI Responses | ✅ multiple output items | ✅ | tracked 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.
| Provider | Text | Image | File | Notes |
|---|---|---|---|---|
| Anthropic | ✅ | ✅ | ✅ | tool_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 Responses | ✅ | ✅ | ✅ | function_call_output takes a content list of input_text, input_image, and input_file |
| Google Gemini | ✅ | ❌ | ❌ | functionResponse.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.
| Provider | auto | none | required / any | specific | pi-go |
|---|---|---|---|---|---|
| Anthropic | ✅ | ✅ | ✅ any | ✅ | ✅ all four (convert.go:215-231) |
| OpenAI Chat | ✅ | ✅ | ✅ required | ✅ | ✅ all four (convert.go:222-241) |
| OpenAI Responses | ✅ | ✅ | ✅ | ✅ | ✅ all four (convert.go:238-261) |
| Google Gemini | ✅ AUTO | ✅ NONE | ✅ ANY | ⚠️ via allowedFunctionNames | ⚠️ |
Provider Documentation
- Anthropic — Tool use
- OpenAI — Function calling
- OpenAI Responses — Tools
- Google Gemini — Function calling
pi-go Gaps
- Strict schema mode plumbed only on OpenAI Chat via compat flag (convert.go:205-206); not exposed as
ToolInfofield, not passed to other providers. OutputSchema(tool.go) defined onToolInfobut not forwarded by any provider.ToolInfo.Parallelflag 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, inANYmode); pi-go’s single-stringToolChoicedoesn’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.