5c807d76a0
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>
171 lines
5.5 KiB
Go
171 lines
5.5 KiB
Go
package datetime
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.yeij.top/AskaEth/Cyrene-Plugins/sdk"
|
|
)
|
|
|
|
type DatetimePlugin struct{ sdk.BasePlugin }
|
|
|
|
func (p *DatetimePlugin) Metadata() sdk.PluginMetadata {
|
|
return sdk.PluginMetadata{
|
|
Name: "datetime", DisplayName: "Date & Time", Version: "1.0.0",
|
|
Description: "Date/time utilities: now, format, arithmetic, diff, timezone list",
|
|
Category: "utility", Author: sdk.PluginAuthor{Name: "Cyrene Team"},
|
|
}
|
|
}
|
|
|
|
func (p *DatetimePlugin) Tools() []sdk.Tool { return []sdk.Tool{&DatetimeTool{}} }
|
|
|
|
type DatetimeTool struct{ sdk.BaseTool }
|
|
|
|
func (t *DatetimeTool) Definition() sdk.ToolDefinition {
|
|
return sdk.ToolDefinition{
|
|
ID: "datetime", Name: "datetime", DisplayName: "Date & Time",
|
|
Description: "Date/time utility. Get current time, format dates, date arithmetic, date diff, list timezones.",
|
|
Category: "utility", Complexity: sdk.ComplexitySimple,
|
|
Parameters: map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"action": map[string]interface{}{"type": "string", "enum": []string{"now", "format", "add", "diff", "timezone_list"}},
|
|
"format": map[string]interface{}{"type": "string"},
|
|
"timezone": map[string]interface{}{"type": "string"},
|
|
"date": map[string]interface{}{"type": "string"},
|
|
"duration": map[string]interface{}{"type": "string"},
|
|
"date2": map[string]interface{}{"type": "string"},
|
|
},
|
|
"required": []string{"action"},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (t *DatetimeTool) Validate(args map[string]interface{}) error {
|
|
if _, ok := args["action"]; !ok {
|
|
return fmt.Errorf("missing required parameter: action")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *DatetimeTool) Execute(_ context.Context, args map[string]interface{}) (*sdk.ToolResult, error) {
|
|
action, _ := args["action"].(string)
|
|
tzStr, _ := args["timezone"].(string)
|
|
loc, _ := parseLocation(tzStr)
|
|
now := time.Now().In(loc)
|
|
|
|
switch action {
|
|
case "now":
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: true,
|
|
Output: fmt.Sprintf("Current time: %s (unix: %d, zone: %s)", now.Format(time.RFC3339), now.Unix(), loc.String())}, nil
|
|
|
|
case "format":
|
|
dateStr, _ := args["date"].(string)
|
|
format, _ := args["format"].(string)
|
|
if format == "" {
|
|
format = time.RFC3339
|
|
}
|
|
parsed, err := parseDate(dateStr, loc)
|
|
if err != nil {
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: err.Error()}, nil
|
|
}
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: true,
|
|
Output: fmt.Sprintf("Formatted: %s", parsed.Format(format))}, nil
|
|
|
|
case "add":
|
|
dateStr, _ := args["date"].(string)
|
|
durStr, _ := args["duration"].(string)
|
|
base := now
|
|
if dateStr != "" {
|
|
var err error
|
|
base, err = parseDate(dateStr, loc)
|
|
if err != nil {
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: err.Error()}, nil
|
|
}
|
|
}
|
|
result, err := addDuration(base, durStr)
|
|
if err != nil {
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: err.Error()}, nil
|
|
}
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: true,
|
|
Output: fmt.Sprintf("%s + %s = %s", base.Format(time.RFC3339), durStr, result.Format(time.RFC3339))}, nil
|
|
|
|
case "diff":
|
|
d1, _ := args["date"].(string)
|
|
d2, _ := args["date2"].(string)
|
|
t1, err := parseDate(d1, loc)
|
|
if err != nil {
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: err.Error()}, nil
|
|
}
|
|
t2, err := parseDate(d2, loc)
|
|
if err != nil {
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: err.Error()}, nil
|
|
}
|
|
diff := t2.Sub(t1)
|
|
if diff < 0 {
|
|
diff = -diff
|
|
}
|
|
days := int(diff.Hours()) / 24
|
|
hours := int(diff.Hours()) % 24
|
|
minutes := int(diff.Minutes()) % 60
|
|
seconds := int(diff.Seconds()) % 60
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: true,
|
|
Output: fmt.Sprintf("Difference: %d days, %d hours, %d minutes, %d seconds", days, hours, minutes, seconds)}, nil
|
|
|
|
case "timezone_list":
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: true,
|
|
Output: "Common timezones: UTC, Asia/Shanghai, Asia/Tokyo, Asia/Seoul, Asia/Singapore, Asia/Kolkata, Asia/Dubai, Europe/London, Europe/Paris, Europe/Moscow, America/New_York, America/Chicago, America/Los_Angeles, America/Sao_Paulo, Australia/Sydney, Pacific/Auckland, Africa/Cairo, Africa/Lagos"}, nil
|
|
|
|
default:
|
|
return &sdk.ToolResult{ToolName: "datetime", Success: false,
|
|
Error: fmt.Sprintf("unknown action: %s", action)}, nil
|
|
}
|
|
}
|
|
|
|
func parseLocation(tz string) (*time.Location, error) {
|
|
if tz == "" {
|
|
loc, err := time.LoadLocation("Asia/Shanghai")
|
|
if err != nil {
|
|
return time.UTC, nil
|
|
}
|
|
return loc, nil
|
|
}
|
|
return time.LoadLocation(tz)
|
|
}
|
|
|
|
func parseDate(s string, loc *time.Location) (time.Time, error) {
|
|
formats := []string{time.RFC3339, "2006-01-02T15:04:05", "2006-01-02 15:04:05", "2006-01-02", "2006/01/02"}
|
|
for _, f := range formats {
|
|
if t, err := time.ParseInLocation(f, s, loc); err == nil {
|
|
return t, nil
|
|
}
|
|
}
|
|
return time.Time{}, fmt.Errorf("cannot parse date: %s", s)
|
|
}
|
|
|
|
func addDuration(t time.Time, durStr string) (time.Time, error) {
|
|
durStr = strings.TrimSpace(durStr)
|
|
if durStr == "" {
|
|
return t, nil
|
|
}
|
|
// Handle months and years
|
|
if strings.Contains(durStr, "M") || strings.Contains(durStr, "y") {
|
|
months := 0
|
|
years := 0
|
|
if strings.Contains(durStr, "y") {
|
|
fmt.Sscanf(durStr, "%dy", &years)
|
|
}
|
|
if strings.Contains(durStr, "M") {
|
|
fmt.Sscanf(durStr, "%dM", &months)
|
|
}
|
|
return t.AddDate(years, months, 0), nil
|
|
}
|
|
d, err := time.ParseDuration(durStr)
|
|
if err != nil {
|
|
return t, fmt.Errorf("invalid duration: %s", durStr)
|
|
}
|
|
return t.Add(d), nil
|
|
}
|