package client import ( "errors" "os" "testing" "github.com/charmbracelet/log" "github.com/google/uuid" "github.com/stretchr/testify/suite" ) type ToolTestSuite struct { suite.Suite handler ToolsHandlers client AgentClient } func (suite *ToolTestSuite) SetupTest() { suite.handler = ToolsHandlers{ handlers: map[string]ToolHandler{}, } suite.handler.AddTool("a", func(info ToolHandlerInfo, args string, call ToolCall) (any, error) { return args, nil }) suite.handler.AddTool("error", func(info ToolHandlerInfo, args string, call ToolCall) (any, error) { return false, errors.New("I will always error") }) suite.client.Log = log.New(os.Stdout) suite.client.ToolHandler = suite.handler } func (suite *ToolTestSuite) TestSingleToolCall() { require := suite.Require() response := suite.handler.Handle( ToolHandlerInfo{ UserId: uuid.Nil, ImageId: uuid.Nil, }, ToolCall{ Index: 0, Id: "1", Function: FunctionCall{ Name: "a", Arguments: "return", }, }) require.EqualValues(response, ChatUserToolResponse{ Role: "tool", Content: "\"return\"", ToolCallId: "1", Name: "a", }) } func (suite *ToolTestSuite) TestMultipleToolCalls() { assert := suite.Assert() require := suite.Require() chat := Chat{ Messages: []ChatMessage{ChatAiMessage{ Role: "assistant", Content: "", ToolCalls: &[]ToolCall{ { Index: 0, Id: "1", Function: FunctionCall{ Name: "a", Arguments: "first-call", }, }, { Index: 1, Id: "2", Function: FunctionCall{ Name: "a", Arguments: "second-call", }, }, }, }}, } err := suite.client.Process( ToolHandlerInfo{ UserId: uuid.Nil, ImageId: uuid.Nil, }, &AgentRequestBody{ Chat: &chat, }) require.NoError(err, "Tool call shouldnt return an error") assert.EqualValues(chat.Messages[1:], []ChatMessage{ ChatUserToolResponse{ Role: "tool", Content: "\"first-call\"", ToolCallId: "1", Name: "a", }, ChatUserToolResponse{ Role: "tool", Content: "\"second-call\"", ToolCallId: "2", Name: "a", }, }) } func (suite *ToolTestSuite) TestMultipleToolCallsWithErrors() { assert := suite.Assert() require := suite.Require() chat := Chat{ Messages: []ChatMessage{ChatAiMessage{ Role: "assistant", Content: "", ToolCalls: &[]ToolCall{ { Index: 0, Id: "1", Function: FunctionCall{ Name: "error", Arguments: "", }, }, { Index: 1, Id: "2", Function: FunctionCall{ Name: "non-existant", Arguments: "", }, }, { Index: 2, Id: "3", Function: FunctionCall{ Name: "a", Arguments: "no-error", }, }, }, }}, } err := suite.client.Process( ToolHandlerInfo{ UserId: uuid.Nil, ImageId: uuid.Nil, }, &AgentRequestBody{ Chat: &chat, }) require.NoError(err, "Tool call shouldnt return an error") assert.EqualValues(chat.Messages[1:], []ChatMessage{ ChatUserToolResponse{ Role: "tool", Content: "I will always error", ToolCallId: "1", Name: "error", }, ChatUserToolResponse{ Role: "tool", Content: "This tool does not exist", ToolCallId: "2", Name: "non-existant", }, ChatUserToolResponse{ Role: "tool", Content: "\"no-error\"", ToolCallId: "3", Name: "a", }, }) } func TestToolSuite(t *testing.T) { suite.Run(t, &ToolTestSuite{ client: AgentClient{}, }) }