Skip to main content

Dynamic Tools

The Go AI SDK does not have a DynamicTool helper function. Instead, a tool is marked as dynamic by setting its Type field to types.ToolTypeDynamic. Dynamic tools are registered and typed at runtime (for example, tools loaded from an MCP server or built from user-supplied configuration) rather than being known at compile time. The SDK tracks dynamic tool calls and results separately from statically defined ones.

Tool.Type​

const (
ToolTypeFunction = "function" // default: locally executed function tool
ToolTypeDynamic = "dynamic" // dynamic tool whose schema can vary at runtime
ToolTypeProviderDefined = "provider" // provider-defined native tool
ToolTypeProviderExecuted = "provider-executed"
)

Setting Type: types.ToolTypeDynamic on a types.Tool tells the SDK this tool's shape isn't known statically. It otherwise has the same fields as any other tool: Name, Description, Parameters, and Execute.

Tracking dynamic tool calls and results​

Results that come from dynamic tools are split out from static ones:

  • ai.GenerateTextResult.DynamicToolCalls []types.ToolCall
  • ai.GenerateTextResult.DynamicToolResults []types.ToolResult
  • ai.StreamTextResult.DynamicToolCalls() []types.ToolCall
  • ai.StreamTextResult.DynamicToolResults() []types.ToolResult
  • types.ToolCall.Dynamic bool and types.ToolResult.Dynamic bool

Examples​

Registering a dynamic tool​

package main

import (
"context"
"fmt"
"log"

"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/provider/types"
"github.com/digitallysavvy/go-ai/pkg/providers/openai"
)

func main() {
p := openai.New(openai.Config{APIKey: "your-api-key"})
model, _ := p.LanguageModel("gpt-4")

searchTool := types.Tool{
Name: "search_db",
Type: types.ToolTypeDynamic,
Description: "Search the database",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"query": map[string]interface{}{"type": "string"},
},
"required": []string{"query"},
},
Execute: func(ctx context.Context, input map[string]interface{}, opts types.ToolExecutionOptions) (interface{}, error) {
query := input["query"].(string)
return []string{"result for " + query}, nil
},
}

result, err := ai.GenerateText(context.Background(), ai.GenerateTextOptions{
Model: model,
Prompt: "Search the database for invoices",
Tools: []types.Tool{searchTool},
StopWhen: []ai.StopCondition{ai.IsStepCount(5)},
})
if err != nil {
log.Fatal(err)
}

fmt.Printf("Dynamic tool calls: %d\n", len(result.DynamicToolCalls))
}

Checking whether a result came from a dynamic tool​

for _, tr := range result.ToolResults {
if tr.Dynamic {
fmt.Printf("dynamic tool %s returned %v\n", tr.ToolName, tr.Result)
}
}

See Also​