tool_test.go

  1package fantasy
  2
  3import (
  4	"context"
  5	"fmt"
  6	"testing"
  7
  8	"github.com/stretchr/testify/require"
  9)
 10
 11// Example of a simple typed tool using the function approach
 12type CalculatorInput struct {
 13	Expression string `json:"expression" description:"Mathematical expression to evaluate"`
 14}
 15
 16func TestTypedToolFuncExample(t *testing.T) {
 17	// Create a typed tool using the function API
 18	tool := NewAgentTool(
 19		"calculator",
 20		"Evaluates simple mathematical expressions",
 21		func(ctx context.Context, input CalculatorInput, _ ToolCall) (ToolResponse, error) {
 22			if input.Expression == "2+2" {
 23				return NewTextResponse("4"), nil
 24			}
 25			return NewTextErrorResponse("unsupported expression"), nil
 26		},
 27	)
 28
 29	// Check the tool info
 30	info := tool.Info()
 31	require.Equal(t, "calculator", info.Name)
 32	require.Len(t, info.Required, 1)
 33	require.Equal(t, "expression", info.Required[0])
 34
 35	// Test execution
 36	call := ToolCall{
 37		ID:    "test-1",
 38		Name:  "calculator",
 39		Input: `{"expression": "2+2"}`,
 40	}
 41
 42	result, err := tool.Run(context.Background(), call)
 43	require.NoError(t, err)
 44	require.Equal(t, "4", result.Content)
 45	require.False(t, result.IsError)
 46}
 47
 48func TestEnumToolExample(t *testing.T) {
 49	type WeatherInput struct {
 50		Location string `json:"location" description:"City name"`
 51		Units    string `json:"units" enum:"celsius,fahrenheit" description:"Temperature units"`
 52	}
 53
 54	// Create a weather tool with enum support
 55	tool := NewAgentTool(
 56		"weather",
 57		"Gets current weather for a location",
 58		func(ctx context.Context, input WeatherInput, _ ToolCall) (ToolResponse, error) {
 59			temp := "22°C"
 60			if input.Units == "fahrenheit" {
 61				temp = "72°F"
 62			}
 63			return NewTextResponse(fmt.Sprintf("Weather in %s: %s, sunny", input.Location, temp)), nil
 64		},
 65	)
 66	// Check that the schema includes enum values
 67	info := tool.Info()
 68	unitsParam, ok := info.Parameters["units"].(map[string]any)
 69	require.True(t, ok, "Expected units parameter to exist")
 70	enumValues, ok := unitsParam["enum"].([]any)
 71	require.True(t, ok)
 72	require.Len(t, enumValues, 2)
 73
 74	// Test execution with enum value
 75	call := ToolCall{
 76		ID:    "test-2",
 77		Name:  "weather",
 78		Input: `{"location": "San Francisco", "units": "fahrenheit"}`,
 79	}
 80
 81	result, err := tool.Run(context.Background(), call)
 82	require.NoError(t, err)
 83	require.Contains(t, result.Content, "San Francisco")
 84	require.Contains(t, result.Content, "72°F")
 85}
 86
 87func TestNewImageResponse(t *testing.T) {
 88	imageData := []byte{0x89, 0x50, 0x4E, 0x47} // PNG header bytes
 89	mediaType := "image/png"
 90
 91	resp := NewImageResponse(imageData, mediaType)
 92
 93	require.Equal(t, "image", resp.Type)
 94	require.Equal(t, imageData, resp.Data)
 95	require.Equal(t, mediaType, resp.MediaType)
 96	require.False(t, resp.IsError)
 97	require.Empty(t, resp.Content)
 98}
 99
100func TestNewMediaResponse(t *testing.T) {
101	audioData := []byte{0x52, 0x49, 0x46, 0x46} // RIFF header bytes
102	mediaType := "audio/wav"
103
104	resp := NewMediaResponse(audioData, mediaType)
105
106	require.Equal(t, "media", resp.Type)
107	require.Equal(t, audioData, resp.Data)
108	require.Equal(t, mediaType, resp.MediaType)
109	require.False(t, resp.IsError)
110	require.Empty(t, resp.Content)
111}