78e3f450c2
- Fix: Session history flash (race condition + WS guard) - Fix: Chat background overlay + sidebar transparency - Fix: IoT device control (Chinese action names, status field) - Feat: Independent memory-service (port 8091, 13 endpoints) - Feat: Independent tool-engine service (port 8092, 13 tools) - Feat: Tool call logs with paginated DevTools panel - Feat: Thinking log records with DevTools panel - Feat: Future development roadmap document - Chore: Updated .gitignore, go.work, DevTools config - Chore: 5-service health check, project review docs
124 lines
3.2 KiB
Go
124 lines
3.2 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/yourname/cyrene-ai/tool-engine/internal/model"
|
|
"github.com/yourname/cyrene-ai/tool-engine/internal/tools"
|
|
)
|
|
|
|
// ToolService 工具执行引擎
|
|
type ToolService struct {
|
|
registry map[string]tools.Tool
|
|
}
|
|
|
|
// NewToolService 创建工具服务,注册所有工具
|
|
func NewToolService(iotClient tools.IoTClientInterface, dataDir string) *ToolService {
|
|
svc := &ToolService{
|
|
registry: make(map[string]tools.Tool),
|
|
}
|
|
|
|
// 注册所有 13 个工具
|
|
svc.Register(tools.NewCalculatorTool())
|
|
svc.Register(tools.NewDateTimeTool())
|
|
svc.Register(tools.NewTextTool())
|
|
svc.Register(tools.NewCryptoTool())
|
|
svc.Register(tools.NewRandomTool())
|
|
svc.Register(tools.NewMarkdownTool())
|
|
svc.Register(tools.NewJSONTool())
|
|
svc.Register(tools.NewFileTool(dataDir))
|
|
svc.Register(tools.NewHTTPTool())
|
|
svc.Register(tools.NewWebSearchTool())
|
|
svc.Register(tools.NewWebFetchTool())
|
|
|
|
// IoT 工具(需要 IoT 客户端)
|
|
if iotClient != nil {
|
|
svc.Register(tools.NewIoTQueryTool(iotClient))
|
|
svc.Register(tools.NewIoTControlTool(iotClient))
|
|
} else {
|
|
log.Println("[tool-service] IoT 客户端未配置,跳过 IoT 工具注册")
|
|
}
|
|
|
|
return svc
|
|
}
|
|
|
|
// Register 注册工具
|
|
func (s *ToolService) Register(tool tools.Tool) {
|
|
def := tool.Definition()
|
|
s.registry[def.Name] = tool
|
|
log.Printf("[tool-service] 已注册工具: %s", def.Name)
|
|
}
|
|
|
|
// ListTools 获取所有工具定义
|
|
func (s *ToolService) ListTools() []model.ToolDefinition {
|
|
defs := make([]model.ToolDefinition, 0, len(s.registry))
|
|
for _, tool := range s.registry {
|
|
defs = append(defs, tool.Definition())
|
|
}
|
|
return defs
|
|
}
|
|
|
|
// GetTool 获取单个工具定义
|
|
func (s *ToolService) GetTool(name string) (*model.ToolDefinition, bool) {
|
|
tool, ok := s.registry[name]
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
def := tool.Definition()
|
|
return &def, true
|
|
}
|
|
|
|
// Execute 执行单个工具
|
|
func (s *ToolService) Execute(ctx context.Context, name string, arguments map[string]interface{}) (*model.ToolResult, error) {
|
|
tool, ok := s.registry[name]
|
|
if !ok {
|
|
return &model.ToolResult{
|
|
Output: "",
|
|
Error: fmt.Sprintf("工具 %s 不存在", name),
|
|
}, nil
|
|
}
|
|
|
|
log.Printf("[tool-service] 执行工具: %s", name)
|
|
result, err := tool.Execute(ctx, arguments)
|
|
if err != nil {
|
|
log.Printf("[tool-service] 工具 %s 执行错误: %v", name, err)
|
|
return &model.ToolResult{
|
|
Output: "",
|
|
Error: fmt.Sprintf("执行工具 %s 失败: %v", name, err),
|
|
}, nil
|
|
}
|
|
|
|
if result.Error != "" {
|
|
log.Printf("[tool-service] 工具 %s 返回错误: %s", name, result.Error)
|
|
} else {
|
|
log.Printf("[tool-service] 工具 %s 执行成功", name)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// ExecuteBatch 批量执行工具调用
|
|
func (s *ToolService) ExecuteBatch(ctx context.Context, calls []model.ToolCall) *model.BatchExecuteResponse {
|
|
results := make([]model.ToolResult, 0, len(calls))
|
|
|
|
for _, call := range calls {
|
|
result, err := s.Execute(ctx, call.Name, call.Arguments)
|
|
if err != nil {
|
|
results = append(results, model.ToolResult{
|
|
ID: call.ID,
|
|
Output: "",
|
|
Error: err.Error(),
|
|
})
|
|
continue
|
|
}
|
|
result.ID = call.ID
|
|
results = append(results, *result)
|
|
}
|
|
|
|
return &model.BatchExecuteResponse{
|
|
Results: results,
|
|
}
|
|
}
|