96 lines
2.9 KiB
Go
96 lines
2.9 KiB
Go
package basic
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// jsonTool exposes JSON parsing, formatting, validation and serialization for the
|
|
// agent. `value` is unconstrained in the schema because it is a string for
|
|
// parse/format/validate and any JSON value for stringify.
|
|
type jsonTool struct{}
|
|
|
|
// Name returns the tool identifier.
|
|
func (jsonTool) Name() string { return "json" }
|
|
|
|
// Description explains what the tool does for the model.
|
|
func (jsonTool) Description() string {
|
|
return "Parse, format, validate or serialize JSON for structured data handling."
|
|
}
|
|
|
|
// Parameters returns the tool input JSON Schema.
|
|
func (jsonTool) Parameters() (map[string]any, error) {
|
|
return map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"operation": map[string]any{
|
|
"type": "string",
|
|
"enum": []any{"parse", "format", "validate", "stringify"},
|
|
"description": "the operation to perform",
|
|
},
|
|
"value": map[string]any{"description": "input: a JSON string for parse/format/validate, any value for stringify"},
|
|
},
|
|
"required": []any{"operation"},
|
|
}, nil
|
|
}
|
|
|
|
// Execute runs the requested operation against value.
|
|
func (jsonTool) 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
|
|
}
|
|
op, err := reqString(m, "operation")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !hasKey(m, "value") {
|
|
return nil, fmt.Errorf("basic: missing required argument %q: %w", "value", ErrInvalidArgument)
|
|
}
|
|
value := m["value"]
|
|
switch strings.ToLower(strings.TrimSpace(op)) {
|
|
case "parse":
|
|
s, ok := value.(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("basic: argument %q must be a string for parse: %w", "value", ErrInvalidArgument)
|
|
}
|
|
var out any
|
|
if err := json.Unmarshal([]byte(s), &out); err != nil {
|
|
return nil, fmt.Errorf("basic: invalid json for parse: %w", err)
|
|
}
|
|
return map[string]any{"result": out}, nil
|
|
case "format":
|
|
s, ok := value.(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("basic: argument %q must be a string for format: %w", "value", ErrInvalidArgument)
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := json.Indent(&buf, []byte(s), "", " "); err != nil {
|
|
return nil, fmt.Errorf("basic: invalid json for format: %w", err)
|
|
}
|
|
return map[string]any{"result": buf.String()}, nil
|
|
case "validate":
|
|
s, ok := value.(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("basic: argument %q must be a string for validate: %w", "value", ErrInvalidArgument)
|
|
}
|
|
return map[string]any{"valid": json.Valid([]byte(s))}, nil
|
|
case "stringify":
|
|
var buf bytes.Buffer
|
|
enc := json.NewEncoder(&buf)
|
|
enc.SetIndent("", " ")
|
|
if err := enc.Encode(value); err != nil {
|
|
return nil, fmt.Errorf("basic: cannot serialize value: %w", err)
|
|
}
|
|
return map[string]any{"result": strings.TrimRight(buf.String(), "\n")}, nil
|
|
default:
|
|
return nil, fmt.Errorf("basic: unknown json operation %q: %w", op, ErrUnsupported)
|
|
}
|
|
}
|