feat(tools/basic): 内置基础工具(calculator(注入安全)/datetime/random/text/json/markdown)+ 批量注册
This commit is contained in:
1 parent
b3c61aa1ff
commit
08223c06a5
19 files changed
+2074
No files matched your search
@@ -0,0 +1,125 @@
|
||||
package basic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// random generates a cryptographically-random integer in [min,max] or a random
|
||||
// string of a given length drawn from a charset. Providing min/max selects the
|
||||
// integer mode; providing length selects the string mode.
|
||||
type random struct{}
|
||||
|
||||
const (
|
||||
// maxRandomLen bounds a generated string length.
|
||||
maxRandomLen = 1024
|
||||
// defaultCharset is the alphabet used when none is supplied.
|
||||
defaultCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
)
|
||||
|
||||
// Name returns the tool identifier.
|
||||
func (random) Name() string { return "random" }
|
||||
|
||||
// Description explains what the tool does for the model.
|
||||
func (random) Description() string {
|
||||
return "Generate a cryptographically-random integer in [min,max] or a random string of a given length."
|
||||
}
|
||||
|
||||
// Parameters returns the tool input JSON Schema.
|
||||
func (random) Parameters() (map[string]any, error) {
|
||||
return map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"min": map[string]any{"type": "integer", "description": "inclusive lower bound for an integer"},
|
||||
"max": map[string]any{"type": "integer", "description": "inclusive upper bound for an integer"},
|
||||
"length": map[string]any{"type": "integer", "description": "length of the random string"},
|
||||
"charset": map[string]any{"type": "string", "description": "characters the string is drawn from"},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Execute produces either an integer or a string depending on which arguments
|
||||
// are supplied.
|
||||
func (random) Execute(ctx context.Context, args any) (any, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := asMap(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hasKey(m, "min") || hasKey(m, "max") {
|
||||
min, err := optInt(m, "min", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
max, err := optInt(m, "max", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v, err := randInt(min, max)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{"value": v}, nil
|
||||
}
|
||||
if hasKey(m, "length") {
|
||||
n, err := reqInt(m, "length")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
charset, err := optString(m, "charset", defaultCharset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := randString(n, charset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{"value": s}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("basic: provide min/max for an integer or length for a string: %w", ErrInvalidArgument)
|
||||
}
|
||||
|
||||
// randInt returns a uniformly-distributed integer in [min,max] inclusive, using
|
||||
// crypto/rand so the result is not predictable from the process state.
|
||||
func randInt(min, max int) (int, error) {
|
||||
if max < min {
|
||||
return 0, fmt.Errorf("basic: max must be >= min: %w", ErrInvalidArgument)
|
||||
}
|
||||
if min == max {
|
||||
return min, nil
|
||||
}
|
||||
span := int64(max) - int64(min) + 1
|
||||
n, err := rand.Int(rand.Reader, big.NewInt(span))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("basic: random source: %w", err)
|
||||
}
|
||||
return int(n.Int64()) + min, nil
|
||||
}
|
||||
|
||||
// randString returns a length-character string drawn uniformly from charset using
|
||||
// crypto/rand (no modulo bias).
|
||||
func randString(length int, charset string) (string, error) {
|
||||
if length < 1 || length > maxRandomLen {
|
||||
return "", fmt.Errorf("basic: length must be between 1 and %d: %w", maxRandomLen, ErrInvalidArgument)
|
||||
}
|
||||
cs := []rune(charset)
|
||||
if len(cs) == 0 {
|
||||
return "", fmt.Errorf("basic: charset must not be empty: %w", ErrInvalidArgument)
|
||||
}
|
||||
var b strings.Builder
|
||||
b.Grow(length)
|
||||
span := big.NewInt(int64(len(cs)))
|
||||
for i := 0; i < length; i++ {
|
||||
n, err := rand.Int(rand.Reader, span)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("basic: random source: %w", err)
|
||||
}
|
||||
b.WriteRune(cs[n.Int64()])
|
||||
}
|
||||
return b.String(), nil
|
||||
}
|
||||
Reference in new issue
Block a user