package http_plugin import ( "context" "fmt" "io" "net/http" "strings" "time" "git.yeij.top/AskaEth/Cyrene_v2/internal/plugin" ) type Plugin struct{ client *http.Client } func New() *Plugin { return &Plugin{client: &http.Client{Timeout: 15 * time.Second}} } func (p *Plugin) Name() string { return "http" } func (p *Plugin) Version() string { return "1.0.0" } func (p *Plugin) Description() string { return "HTTP请求" } func (p *Plugin) Init(_ context.Context, _ plugin.PluginConfig) error { return nil } func (p *Plugin) Close() error { return nil } func (p *Plugin) Enabled() bool { return true } func (p *Plugin) Tools() []plugin.ToolDefinition { return []plugin.ToolDefinition{{ Name: "http_request", Description: "Send an HTTP request and return the status code and body (truncated).", Parameters: map[string]any{ "type": "object", "properties": map[string]any{ "url": map[string]string{"type": "string", "description": "Request URL (http/https)"}, "method": map[string]string{"type": "string", "description": "GET | POST | PUT | DELETE (default GET)"}, "body": map[string]string{"type": "string", "description": "Optional request body"}, }, "required": []string{"url"}, }, }} } func (p *Plugin) Execute(ctx context.Context, _ string, params map[string]any) (string, error) { rawURL, _ := params["url"].(string) if !strings.HasPrefix(rawURL, "http://") && !strings.HasPrefix(rawURL, "https://") { return "", fmt.Errorf("url must start with http:// or https://") } method := strings.ToUpper(strings.TrimSpace(paramStr(params, "method"))) switch method { case "": method = "GET" case "GET", "POST", "PUT", "DELETE", "PATCH": default: return "", fmt.Errorf("unsupported method %q", method) } var bodyReader io.Reader if body := paramStr(params, "body"); body != "" { bodyReader = strings.NewReader(body) } req, err := http.NewRequestWithContext(ctx, method, rawURL, bodyReader) if err != nil { return "", err } if bodyReader != nil { req.Header.Set("Content-Type", "application/json") } resp, err := p.client.Do(req) if err != nil { return "", fmt.Errorf("request: %w", err) } defer resp.Body.Close() body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20)) if err != nil { return "", fmt.Errorf("read body: %w", err) } text := string(body) if runes := []rune(text); len(runes) > 4000 { text = string(runes[:4000]) + "\n…(响应过长已截断)" } return fmt.Sprintf("HTTP %d\n%s", resp.StatusCode, text), nil } func paramStr(params map[string]any, key string) string { v, _ := params[key].(string) return v }