mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-04 16:13:47 +00:00
124 lines
3.8 KiB
Go
124 lines
3.8 KiB
Go
package mcp
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
func (t *BridgeTool) normalizeArgsForSchema(args map[string]any) (map[string]any, []string, error) {
|
|
if len(args) == 0 {
|
|
return args, nil, nil
|
|
}
|
|
|
|
normalized, coercedPaths, err := normalizeValueForSchema(args, t.inputSchema, "$")
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
normalizedArgs, ok := normalized.(map[string]any)
|
|
if !ok {
|
|
return nil, nil, fmt.Errorf("arguments must be object, got %s", valueKind(normalized))
|
|
}
|
|
return normalizedArgs, coercedPaths, nil
|
|
}
|
|
|
|
func normalizeValueForSchema(value any, schema map[string]any, path string) (any, []string, error) {
|
|
if schema == nil {
|
|
return value, nil, nil
|
|
}
|
|
|
|
types := schemaTypeSet(schema)
|
|
expectsContainer := (types["object"] || types["array"]) && !types["string"]
|
|
if s, ok := value.(string); ok && expectsContainer {
|
|
return normalizeStringContainer(s, schema, types, path)
|
|
}
|
|
|
|
if obj, ok := value.(map[string]any); ok {
|
|
return normalizeObjectValue(obj, schema, path)
|
|
}
|
|
if arr, ok := value.([]any); ok {
|
|
return normalizeArrayValue(arr, schema, path)
|
|
}
|
|
return value, nil, nil
|
|
}
|
|
|
|
func normalizeStringContainer(raw string, schema map[string]any, types map[string]bool, path string) (any, []string, error) {
|
|
trimmed := strings.TrimSpace(raw)
|
|
if trimmed == "" {
|
|
return nil, nil, fmt.Errorf("%s must be %s, got empty string", path, expectedContainerLabel(types))
|
|
}
|
|
|
|
var decoded any
|
|
if err := json.Unmarshal([]byte(trimmed), &decoded); err != nil {
|
|
return nil, nil, fmt.Errorf("%s must be %s, got JSON string that cannot be parsed: pass a native value instead of a stringified JSON value", path, expectedContainerLabel(types))
|
|
}
|
|
|
|
switch v := decoded.(type) {
|
|
case map[string]any:
|
|
if !types["object"] {
|
|
return nil, nil, fmt.Errorf("%s must be %s, got JSON string containing object", path, expectedContainerLabel(types))
|
|
}
|
|
normalized, nestedPaths, err := normalizeObjectValue(v, schema, path)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return normalized, prependPath(path, nestedPaths), nil
|
|
case []any:
|
|
if !types["array"] {
|
|
return nil, nil, fmt.Errorf("%s must be %s, got JSON string containing array", path, expectedContainerLabel(types))
|
|
}
|
|
normalized, nestedPaths, err := normalizeArrayValue(v, schema, path)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return normalized, prependPath(path, nestedPaths), nil
|
|
default:
|
|
return nil, nil, fmt.Errorf("%s must be %s, got JSON string containing %s", path, expectedContainerLabel(types), valueKind(decoded))
|
|
}
|
|
}
|
|
|
|
func normalizeObjectValue(obj map[string]any, schema map[string]any, path string) (map[string]any, []string, error) {
|
|
props, _ := schema["properties"].(map[string]any)
|
|
if len(props) == 0 {
|
|
return obj, nil, nil
|
|
}
|
|
|
|
normalized := make(map[string]any, len(obj))
|
|
var coercedPaths []string
|
|
for key, value := range obj {
|
|
propSchema, _ := props[key].(map[string]any)
|
|
if propSchema == nil {
|
|
normalized[key] = value
|
|
continue
|
|
}
|
|
nextPath := joinSchemaPath(path, key)
|
|
nextValue, nestedPaths, err := normalizeValueForSchema(value, propSchema, nextPath)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
normalized[key] = nextValue
|
|
coercedPaths = append(coercedPaths, nestedPaths...)
|
|
}
|
|
return normalized, coercedPaths, nil
|
|
}
|
|
|
|
func normalizeArrayValue(arr []any, schema map[string]any, path string) ([]any, []string, error) {
|
|
itemSchema, _ := schema["items"].(map[string]any)
|
|
if itemSchema == nil {
|
|
return arr, nil, nil
|
|
}
|
|
|
|
normalized := make([]any, len(arr))
|
|
var coercedPaths []string
|
|
for i, value := range arr {
|
|
nextPath := fmt.Sprintf("%s[%d]", path, i)
|
|
nextValue, nestedPaths, err := normalizeValueForSchema(value, itemSchema, nextPath)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
normalized[i] = nextValue
|
|
coercedPaths = append(coercedPaths, nestedPaths...)
|
|
}
|
|
return normalized, coercedPaths, nil
|
|
}
|