Initial commit: Cyrene Plugins SDK + Plugin Manager

Extracted from Cyrene main repo (backend/pkg/plugins + backend/plugin-manager).
Contains SDK interfaces (Plugin/Tool/HostAPI), 13 built-in plugins,
ToolRegistry with call log ring buffer, and Plugin Manager REST API service.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 09:49:12 +08:00
commit 5c807d76a0
27 changed files with 3609 additions and 0 deletions
+132
View File
@@ -0,0 +1,132 @@
package jsonplugin
import (
"context"
"encoding/json"
"fmt"
"strconv"
"strings"
"git.yeij.top/AskaEth/Cyrene-Plugins/sdk"
)
type JSONPlugin struct{ sdk.BasePlugin }
func (p *JSONPlugin) Metadata() sdk.PluginMetadata {
return sdk.PluginMetadata{
Name: "json", DisplayName: "JSON Processor", Version: "1.0.0",
Description: "JSON parsing, dot-path query, validation, pretty-print",
Category: "format", Author: sdk.PluginAuthor{Name: "Cyrene Team"},
}
}
func (p *JSONPlugin) Tools() []sdk.Tool { return []sdk.Tool{&JSONTool{}} }
type JSONTool struct{ sdk.BaseTool }
func (t *JSONTool) Definition() sdk.ToolDefinition {
return sdk.ToolDefinition{
ID: "json_ops", Name: "json_ops", DisplayName: "JSON Processor",
Description: "JSON processing. Parse/pretty-print, query by dot-notation path, validate.",
Category: "format", Complexity: sdk.ComplexitySimple,
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"action": map[string]interface{}{"type": "string", "enum": []string{"parse", "query", "validate"}},
"json_string": map[string]interface{}{"type": "string"},
"path": map[string]interface{}{"type": "string"},
},
"required": []string{"action", "json_string"},
},
}
}
func (t *JSONTool) Validate(args map[string]interface{}) error {
for _, k := range []string{"action", "json_string"} {
if _, ok := args[k]; !ok {
return fmt.Errorf("missing required parameter: %s", k)
}
}
return nil
}
func (t *JSONTool) Execute(_ context.Context, args map[string]interface{}) (*sdk.ToolResult, error) {
action, _ := args["action"].(string)
jsonStr, _ := args["json_string"].(string)
switch action {
case "parse":
var v interface{}
if err := json.Unmarshal([]byte(jsonStr), &v); err != nil {
return &sdk.ToolResult{ToolName: "json_ops", Success: false, Error: err.Error()}, nil
}
pretty, err := json.MarshalIndent(v, "", " ")
if err != nil {
return &sdk.ToolResult{ToolName: "json_ops", Success: false, Error: err.Error()}, nil
}
return &sdk.ToolResult{ToolName: "json_ops", Success: true, Output: string(pretty)}, nil
case "query":
var v interface{}
if err := json.Unmarshal([]byte(jsonStr), &v); err != nil {
return &sdk.ToolResult{ToolName: "json_ops", Success: false, Error: err.Error()}, nil
}
path, _ := args["path"].(string)
if path == "" {
return &sdk.ToolResult{ToolName: "json_ops", Success: false, Error: "path is required for query"}, nil
}
result, err := jsonPathQuery(v, path)
if err != nil {
return &sdk.ToolResult{ToolName: "json_ops", Success: false, Error: err.Error()}, nil
}
out, _ := json.Marshal(result)
return &sdk.ToolResult{ToolName: "json_ops", Success: true, Output: string(out)}, nil
case "validate":
var v interface{}
if err := json.Unmarshal([]byte(jsonStr), &v); err != nil {
return &sdk.ToolResult{ToolName: "json_ops", Success: true, Output: "Invalid JSON: " + err.Error()}, nil
}
typeStr := "unknown"
switch v.(type) {
case map[string]interface{}:
typeStr = "object"
case []interface{}:
typeStr = "array"
case string:
typeStr = "string"
case float64:
typeStr = "number"
case bool:
typeStr = "boolean"
}
return &sdk.ToolResult{ToolName: "json_ops", Success: true,
Output: fmt.Sprintf("Valid JSON (type: %s, size: %d bytes)", typeStr, len(jsonStr))}, nil
}
return &sdk.ToolResult{ToolName: "json_ops", Success: false, Error: "unknown action: " + action}, nil
}
func jsonPathQuery(root interface{}, path string) (interface{}, error) {
path = strings.TrimPrefix(path, "$.")
parts := strings.Split(path, ".")
current := root
for _, part := range parts {
switch v := current.(type) {
case map[string]interface{}:
var ok bool
current, ok = v[part]
if !ok {
return nil, fmt.Errorf("key %q not found", part)
}
case []interface{}:
idx, err := strconv.Atoi(part)
if err != nil || idx < 0 || idx >= len(v) {
return nil, fmt.Errorf("invalid array index: %s", part)
}
current = v[idx]
default:
return nil, fmt.Errorf("cannot traverse into %T at path segment %q", current, part)
}
}
return current, nil
}