Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions pkg/api/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package api

import "fmt"

// ErrInvalidInt64Type is returned when a value cannot be converted to int64.
type ErrInvalidInt64Type struct {
Value interface{}
}

func (e *ErrInvalidInt64Type) Error() string {
return fmt.Sprintf("expected integer, got %T", e.Value)
}

// ParseInt64 converts an interface{} value (typically from JSON-decoded tool arguments)
// to int64. Handles float64 (JSON numbers), int, and int64 types.
// Returns the converted value and nil error on success, or 0 and an ErrInvalidInt64Type if the type is unsupported.
func ParseInt64(value interface{}) (int64, error) {
switch v := value.(type) {
case float64:
return int64(v), nil
case int:
return int64(v), nil
case int64:
return v, nil
default:
return 0, &ErrInvalidInt64Type{Value: value}
}
}
105 changes: 105 additions & 0 deletions pkg/api/params_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package api

import (
"testing"

"github.com/stretchr/testify/suite"
)

type ParamsSuite struct {
suite.Suite
}

func TestParamsSuite(t *testing.T) {
suite.Run(t, new(ParamsSuite))
}

func (s *ParamsSuite) TestParseInt64() {
s.Run("float64 value is converted to int64", func() {
result, err := ParseInt64(float64(42.0))
s.NoError(err)
s.Equal(int64(42), result)
})

s.Run("float64 with decimal truncates to int64", func() {
result, err := ParseInt64(float64(42.9))
s.NoError(err)
s.Equal(int64(42), result)
})

s.Run("int value is converted to int64", func() {
result, err := ParseInt64(int(100))
s.NoError(err)
s.Equal(int64(100), result)
})

s.Run("int64 value is returned as-is", func() {
result, err := ParseInt64(int64(999))
s.NoError(err)
s.Equal(int64(999), result)
})

s.Run("negative float64 value is converted correctly", func() {
result, err := ParseInt64(float64(-10.0))
s.NoError(err)
s.Equal(int64(-10), result)
})

s.Run("negative int value is converted correctly", func() {
result, err := ParseInt64(int(-5))
s.NoError(err)
s.Equal(int64(-5), result)
})

s.Run("zero value is handled correctly", func() {
result, err := ParseInt64(float64(0))
s.NoError(err)
s.Equal(int64(0), result)
})

s.Run("string value returns error", func() {
result, err := ParseInt64("not a number")
s.Error(err)
s.Equal(int64(0), result)
s.Contains(err.Error(), "string")
})

s.Run("nil value returns error", func() {
result, err := ParseInt64(nil)
s.Error(err)
s.Equal(int64(0), result)
})

s.Run("bool value returns error", func() {
result, err := ParseInt64(true)
s.Error(err)
s.Equal(int64(0), result)
s.Contains(err.Error(), "bool")
})

s.Run("slice value returns error", func() {
result, err := ParseInt64([]int{1, 2, 3})
s.Error(err)
s.Equal(int64(0), result)
})

s.Run("map value returns error", func() {
result, err := ParseInt64(map[string]int{"a": 1})
s.Error(err)
s.Equal(int64(0), result)
})
}

func (s *ParamsSuite) TestErrInvalidInt64Type() {
s.Run("error includes type information", func() {
err := &ErrInvalidInt64Type{Value: "test"}
s.Contains(err.Error(), "string")
})

s.Run("error can be type asserted", func() {
_, err := ParseInt64("invalid")
var typeErr *ErrInvalidInt64Type
s.ErrorAs(err, &typeErr)
s.Equal("invalid", typeErr.Value)
})
}
13 changes: 4 additions & 9 deletions pkg/toolsets/core/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,10 @@ func nodesLog(params api.ToolHandlerParams) (*api.ToolCallResult, error) {
tailLines := params.GetArguments()["tailLines"]
var tailInt int64
if tailLines != nil {
// Convert to int64 - safely handle both float64 (JSON number) and int types
switch v := tailLines.(type) {
case float64:
tailInt = int64(v)
case int:
case int64:
tailInt = v
default:
return api.NewToolCallResult("", fmt.Errorf("failed to parse tail parameter: expected integer, got %T", tailLines)), nil
var err error
tailInt, err = api.ParseInt64(tailLines)
if err != nil {
return api.NewToolCallResult("", fmt.Errorf("failed to parse tailLines parameter: %w", err)), nil
}
}
ret, err := params.NodesLog(params, name, query, tailInt)
Expand Down
14 changes: 4 additions & 10 deletions pkg/toolsets/core/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,16 +397,10 @@ func podsLog(params api.ToolHandlerParams) (*api.ToolCallResult, error) {
tail := params.GetArguments()["tail"]
var tailInt int64
if tail != nil {
// Convert to int64 - safely handle both float64 (JSON number) and int types
switch v := tail.(type) {
case float64:
tailInt = int64(v)
case int:
tailInt = int64(v)
case int64:
tailInt = v
default:
return api.NewToolCallResult("", fmt.Errorf("failed to parse tail parameter: expected integer, got %T", tail)), nil
var err error
tailInt, err = api.ParseInt64(tail)
if err != nil {
return api.NewToolCallResult("", fmt.Errorf("failed to parse tail parameter: %w", err)), nil
}
}

Expand Down
13 changes: 4 additions & 9 deletions pkg/toolsets/core/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,16 +346,11 @@ func resourcesScale(params api.ToolHandlerParams) (*api.ToolCallResult, error) {
}

func parseScaleValue(desiredScale interface{}) (int64, error) {
switch s := desiredScale.(type) {
case float64:
return int64(s), nil
case int:
return int64(s), nil
case int64:
return s, nil
default:
return 0, fmt.Errorf("failed to parse scale parameter: expected integer, got %T", desiredScale)
v, err := api.ParseInt64(desiredScale)
if err != nil {
return 0, fmt.Errorf("failed to parse scale parameter: %w", err)
}
return v, nil
}

func parseGroupVersionKind(arguments map[string]interface{}) (*schema.GroupVersionKind, error) {
Expand Down
11 changes: 4 additions & 7 deletions pkg/toolsets/kiali/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,11 @@ func workloadLogsHandler(params api.ToolHandlerParams) (*api.ToolCallResult, err

// Convert tail to maxLines
if tail != nil {
switch v := tail.(type) {
case float64:
maxLines = fmt.Sprintf("%.0f", v)
case int:
maxLines = fmt.Sprintf("%d", v)
case int64:
maxLines = fmt.Sprintf("%d", v)
tailInt, err := api.ParseInt64(tail)
if err != nil {
return api.NewToolCallResult("", fmt.Errorf("failed to parse tail parameter: %w", err)), nil
}
maxLines = fmt.Sprintf("%d", tailInt)
}

// If no container specified, we need to get workload details first to find the main app container
Expand Down