[Bug] llmagent is only compatible with functiontool where input is a struct
Problem
functiontool can be used in contexts other than llmagent so any Type parameter constraints make sense:
type Func[TArgs, TResults any] func(tool.Context, TArgs) (TResults, error)
But llmagent is incompatible with functiontools where input is a non-struct type, because genai.FunctionCall.Args is a map:
Args map[string]any `json:"args,omitempty"`
The result is that an agent can never succeed in calling such tool.
Desired behavior
One of:
- Validate tools in
llmagent.Newand report tool incompatibility as an error. - Make
llmagentwrap such tools in a special decorator which will be handling unboxing of llm-provided arguments of form likemap[string]any{"input": arg}. It will need to override input schema as well.
Reproduction
The agent will never succeed in running the super_tool:
func main() {
ctx := context.Background()
model, err := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{
APIKey: os.Getenv("GOOGLE_API_KEY"),
})
if err != nil {
log.Fatalf("Failed to create model: %v", err)
}
superTool, err := functiontool.New(functiontool.Config{Name: "super_tool"}, functiontool.Func[string, string](
func(ctx tool.Context, input string) (string, error) {
return "Hello", nil
},
))
if err != nil {
log.Fatalf("Failed to create a tool: %v", err)
}
a, err := llmagent.New(llmagent.Config{
Name: "super_tool_caller",
Model: model,
Description: "Agent to invoke the super_tool",
Instruction: "Your SOLE purpose is to invoke the super_tool and pass the result to me.",
Tools: []tool.Tool{superTool},
})
if err != nil {
log.Fatalf("Failed to create agent: %v", err)
}
l := full.NewLauncher()
if err = l.Execute(ctx, &launcher.Config{AgentLoader: agent.NewSingleLoader(a)}, os.Args[1:]); err != nil {
log.Fatalf("Run failed: %v\n\n%s", err, l.CommandLineSyntax())
}
}
Hi Yaroslav,
Thanks for the detailed bug report. I agree, and I prefer your 1st suggestion: Validate tools in llmagent.New and report incompatibility as an error.
This approach is more explicit and easier to maintain. Relaxing validation later is safer than changing implicit decorator behavior, which could break existing users.