Merge pull request #38 from hobbyistlabs-coder/add-calculator-tool-4063054368676444234
feat: add calculator tool for evaluating mathematical expressions
This commit is contained in:
commit
7ddb17f979
5 changed files with 136 additions and 0 deletions
1
go.mod
1
go.mod
|
|
@ -3,6 +3,7 @@ module jane
|
|||
go 1.25.7
|
||||
|
||||
require (
|
||||
github.com/Knetic/govaluate v3.0.0+incompatible
|
||||
github.com/adhocore/gronx v1.19.6
|
||||
github.com/alpacahq/alpaca-trade-api-go/v3 v3.9.1
|
||||
github.com/anthropics/anthropic-sdk-go v1.22.1
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@ func NewAgentInstance(
|
|||
}
|
||||
}
|
||||
|
||||
if cfg.Tools.IsToolEnabled("calculator") {
|
||||
toolsRegistry.Register(tools.NewCalculatorTool())
|
||||
}
|
||||
|
||||
sessionsDir := filepath.Join(workspace, "sessions")
|
||||
sessions := initSessionStore(sessionsDir)
|
||||
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ type ToolsConfig struct {
|
|||
WriteFile ToolConfig `json:"write_file" envPrefix:"PICOCLAW_TOOLS_WRITE_FILE_"`
|
||||
BrowserAction ToolConfig `json:"browser_action" envPrefix:"PICOCLAW_TOOLS_BROWSER_ACTION_"`
|
||||
GoEval ToolConfig `json:"go_eval" envPrefix:"PICOCLAW_TOOLS_GO_EVAL_"`
|
||||
Calculator ToolConfig `json:"calculator" envPrefix:"PICOCLAW_TOOLS_CALCULATOR_"`
|
||||
}
|
||||
|
||||
type SearchCacheConfig struct {
|
||||
|
|
@ -235,6 +236,8 @@ func (t *ToolsConfig) IsToolEnabled(name string) bool {
|
|||
return t.MCP.Enabled
|
||||
case "mcp2cli":
|
||||
return t.MCP2Cli.Enabled
|
||||
case "calculator":
|
||||
return t.Calculator.Enabled
|
||||
default:
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
58
pkg/tools/calculator.go
Normal file
58
pkg/tools/calculator.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Knetic/govaluate"
|
||||
)
|
||||
|
||||
// CalculatorTool evaluates mathematical expressions.
|
||||
type CalculatorTool struct{}
|
||||
|
||||
// NewCalculatorTool creates a new CalculatorTool.
|
||||
func NewCalculatorTool() *CalculatorTool {
|
||||
return &CalculatorTool{}
|
||||
}
|
||||
|
||||
func (t *CalculatorTool) Name() string {
|
||||
return "calculator"
|
||||
}
|
||||
|
||||
func (t *CalculatorTool) Description() string {
|
||||
return "Evaluates mathematical expressions. Input should be a mathematical expression as a string."
|
||||
}
|
||||
|
||||
func (t *CalculatorTool) Parameters() map[string]any {
|
||||
return map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"expression": map[string]any{
|
||||
"type": "string",
|
||||
"description": "The mathematical expression to evaluate (e.g., '2 + 2', '10 * (5 - 3)').",
|
||||
},
|
||||
},
|
||||
"required": []string{"expression"},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *CalculatorTool) Execute(ctx context.Context, args map[string]any) *ToolResult {
|
||||
exprStr, ok := args["expression"].(string)
|
||||
if !ok || exprStr == "" {
|
||||
return ErrorResult("expression argument is required and must be a string")
|
||||
}
|
||||
|
||||
expression, err := govaluate.NewEvaluableExpression(exprStr)
|
||||
if err != nil {
|
||||
return ErrorResult(fmt.Sprintf("invalid expression: %v", err))
|
||||
}
|
||||
|
||||
result, err := expression.Evaluate(nil)
|
||||
if err != nil {
|
||||
return ErrorResult(fmt.Sprintf("evaluation failed: %v", err))
|
||||
}
|
||||
|
||||
// Format result to handle floats properly if needed
|
||||
resStr := fmt.Sprintf("%v", result)
|
||||
return UserResult(resStr)
|
||||
}
|
||||
70
pkg/tools/calculator_test.go
Normal file
70
pkg/tools/calculator_test.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCalculatorTool_Execute(t *testing.T) {
|
||||
calc := NewCalculatorTool()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expression string
|
||||
want string
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "simple addition",
|
||||
expression: "2 + 2",
|
||||
want: "4",
|
||||
},
|
||||
{
|
||||
name: "complex math",
|
||||
expression: "10 * (5 - 3)",
|
||||
want: "20",
|
||||
},
|
||||
{
|
||||
name: "floating point result",
|
||||
expression: "10 / 4",
|
||||
want: "2.5",
|
||||
},
|
||||
{
|
||||
name: "missing expression",
|
||||
expression: "",
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "invalid expression",
|
||||
expression: "2 + * 2",
|
||||
wantError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
args := map[string]any{}
|
||||
if tt.expression != "" {
|
||||
args["expression"] = tt.expression
|
||||
}
|
||||
|
||||
result := calc.Execute(context.Background(), args)
|
||||
|
||||
if tt.wantError {
|
||||
assert.True(t, result.IsError)
|
||||
} else {
|
||||
assert.False(t, result.IsError)
|
||||
assert.Equal(t, tt.want, result.ForLLM)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculatorTool_Info(t *testing.T) {
|
||||
calc := NewCalculatorTool()
|
||||
assert.Equal(t, "calculator", calc.Name())
|
||||
assert.NotEmpty(t, calc.Description())
|
||||
assert.NotNil(t, calc.Parameters())
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue