Files
Cyrene/backend/pkg/plugins/http/plugin.go
T
AskaEth 71f0a1abdb feat: Go模块路径迁移 + Docker生产部署适配 + ethend Docker兼容
- 所有Go模块路径从 github.com/yourname/cyrene-ai 迁移到 git.yeij.top/AskaEth/Cyrene
- 5个Go Dockerfile添加 GOPROXY=https://goproxy.cn,direct 解决国内构建问题
- ai-core go.mod 添加 pkg/plugins replace 指令
- Caddyfile 简化为 http:// 通配 + handle 保留 /api 前缀
- ethend Dockerfile 适配 (npm install + 仅 COPY package.json)
- ethend 新增 RUNNING_IN_DOCKER 环境变量,健康检查改用Docker服务名
- ethend 数据库状态检查支持Docker hostname (postgres/redis/qdrant/minio)
- process-manager 新增 CONTAINER_SVC_MAP + Docker模式自动检测
- 统一 docker-compose.dev.db.yml 卷名 (pg_data/redis_data/qdrant_data/minio_data)
- docker-compose.yml ethend服务挂载docker.sock + 端口变量化
- 清理 .env 统一后的残留文件与提示信息

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 13:43:22 +08:00

123 lines
3.6 KiB
Go

package http
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"time"
"git.yeij.top/AskaEth/Cyrene/pkg/plugins/sdk"
)
type HTTPPlugin struct {
sdk.BasePlugin
client *http.Client
}
func NewHTTPPlugin() *HTTPPlugin {
return &HTTPPlugin{client: &http.Client{Timeout: 10 * time.Second}}
}
func (p *HTTPPlugin) Metadata() sdk.PluginMetadata {
return sdk.PluginMetadata{
Name: "http", DisplayName: "HTTP Client", Version: "1.0.0",
Description: "Send arbitrary HTTP requests with custom methods, headers, body",
Category: "network", Author: sdk.PluginAuthor{Name: "Cyrene Team"},
}
}
func (p *HTTPPlugin) Tools() []sdk.Tool { return []sdk.Tool{&HTTPTool{client: p.client}} }
type HTTPTool struct {
sdk.BaseTool
client *http.Client
}
func (t *HTTPTool) Definition() sdk.ToolDefinition {
return sdk.ToolDefinition{
ID: "http_request", Name: "http_request", DisplayName: "HTTP Client",
Description: "Send arbitrary HTTP requests. Supports custom methods, headers, and body.",
Category: "network", Complexity: sdk.ComplexitySimple,
DangerLevel: "low",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"url": map[string]interface{}{"type": "string"},
"method": map[string]interface{}{"type": "string", "enum": []string{"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"}},
"headers": map[string]interface{}{"type": "object"},
"body": map[string]interface{}{"type": "string"},
"timeout": map[string]interface{}{"type": "number"},
},
"required": []string{"url"},
},
}
}
var allowedMethods = map[string]bool{
"GET": true, "POST": true, "PUT": true, "DELETE": true,
"PATCH": true, "HEAD": true, "OPTIONS": true,
}
func (t *HTTPTool) Validate(args map[string]interface{}) error {
if _, ok := args["url"]; !ok {
return fmt.Errorf("missing required parameter: url")
}
return nil
}
func (t *HTTPTool) Execute(_ context.Context, args map[string]interface{}) (*sdk.ToolResult, error) {
urlStr, _ := args["url"].(string)
method, _ := args["method"].(string)
if method == "" {
method = "GET"
}
if !allowedMethods[method] {
return &sdk.ToolResult{ToolName: "http_request", Success: false, Error: "invalid method: " + method}, nil
}
if !strings.HasPrefix(urlStr, "http://") && !strings.HasPrefix(urlStr, "https://") {
return &sdk.ToolResult{ToolName: "http_request", Success: false, Error: "only http/https URLs allowed"}, nil
}
var bodyReader io.Reader
if body, _ := args["body"].(string); body != "" {
bodyReader = strings.NewReader(body)
}
req, err := http.NewRequest(method, urlStr, bodyReader)
if err != nil {
return &sdk.ToolResult{ToolName: "http_request", Success: false, Error: err.Error()}, nil
}
req.Header.Set("User-Agent", "CyreneBot/1.0")
if headers, ok := args["headers"].(map[string]interface{}); ok {
for k, v := range headers {
req.Header.Set(k, fmt.Sprint(v))
}
}
client := t.client
if timeout, _ := args["timeout"].(float64); timeout > 0 {
client = &http.Client{Timeout: time.Duration(timeout) * time.Second}
}
resp, err := client.Do(req)
if err != nil {
return &sdk.ToolResult{ToolName: "http_request", Success: false, Error: err.Error()}, nil
}
defer resp.Body.Close()
bodyBytes, _ := io.ReadAll(io.LimitReader(resp.Body, 50*1024))
return &sdk.ToolResult{ToolName: "http_request", Success: resp.StatusCode < 500, Output: fmt.Sprintf(
"HTTP %d\n%s\n\n%s", resp.StatusCode, formatHeaders(resp.Header), string(bodyBytes))}, nil
}
func formatHeaders(h http.Header) string {
var lines []string
for k, v := range h {
lines = append(lines, fmt.Sprintf("%s: %s", k, strings.Join(v, ", ")))
}
return strings.Join(lines, "\n")
}