Files
ai-agent/internal/ai/runtime/executor/tooling.go
T

186 lines
5.3 KiB
Go
Raw Normal View History

package executor
import (
"encoding/json"
"strings"
"agent-desk/internal/ai/runtime/registry"
runtimetooling "agent-desk/internal/ai/runtime/tooling"
"agent-desk/internal/models"
"agent-desk/internal/pkg/toolx"
einotool "github.com/cloudwego/eino/components/tool"
)
type preparedTooling struct {
definitions []runtimetooling.MCPToolDefinition
toolCodes []string
toolDefsByModelName map[string]string
staticToolCodes []string
staticTools []einotool.BaseTool
staticToolCodeMap map[string]string
staticToolMetadata map[string]registry.ToolMetadata
}
func prepareTooling(defs []runtimetooling.MCPToolDefinition, selectedSkill *models.SkillDefinition, toolSet *registry.ToolSet, includeSkillTool bool) preparedTooling {
filteredDefs := filterToolDefinitionsBySkill(defs, selectedSkill)
ret := preparedTooling{
definitions: filteredDefs,
toolCodes: make([]string, 0, len(filteredDefs)+2),
toolDefsByModelName: make(map[string]string, len(filteredDefs)),
staticToolCodes: staticToolCodeList(toolSet),
staticTools: toolSetStaticTools(toolSet),
staticToolCodeMap: toolSetStaticToolCodes(toolSet),
staticToolMetadata: toolSetStaticToolMetadata(toolSet),
}
for _, item := range filteredDefs {
toolCode := strings.TrimSpace(item.ToolCode)
modelName := strings.TrimSpace(item.ModelName)
if toolCode == "" || modelName == "" {
continue
}
ret.toolCodes = appendIfMissing(ret.toolCodes, toolCode)
ret.toolDefsByModelName[modelName] = toolCode
}
if len(filteredDefs) > 0 {
ret.toolCodes = appendIfMissing(ret.toolCodes, toolx.BuiltinToolSearch.Code)
ret.toolDefsByModelName[toolx.BuiltinToolSearch.Name] = toolx.BuiltinToolSearch.Code
}
if includeSkillTool {
ret.toolCodes = appendIfMissing(ret.toolCodes, toolx.BuiltinSkill.Code)
ret.toolDefsByModelName[toolx.BuiltinSkill.Name] = toolx.BuiltinSkill.Code
}
for modelName, toolCode := range ret.staticToolCodeMap {
modelName = strings.TrimSpace(modelName)
toolCode = strings.TrimSpace(toolCode)
if modelName == "" || toolCode == "" {
continue
}
ret.toolCodes = appendIfMissing(ret.toolCodes, toolCode)
ret.toolDefsByModelName[modelName] = toolCode
}
return ret
}
func toolSetStaticTools(toolSet *registry.ToolSet) []einotool.BaseTool {
if toolSet == nil {
return nil
}
return append([]einotool.BaseTool(nil), toolSet.StaticTools...)
}
func toolSetStaticToolCodes(toolSet *registry.ToolSet) map[string]string {
if toolSet == nil || len(toolSet.StaticToolCodes) == 0 {
return nil
}
ret := make(map[string]string, len(toolSet.StaticToolCodes))
for name, code := range toolSet.StaticToolCodes {
ret[strings.TrimSpace(name)] = strings.TrimSpace(code)
}
return ret
}
func toolSetStaticToolMetadata(toolSet *registry.ToolSet) map[string]registry.ToolMetadata {
if toolSet == nil || len(toolSet.StaticToolMetadata) == 0 {
return nil
}
ret := make(map[string]registry.ToolMetadata, len(toolSet.StaticToolMetadata))
for name, item := range toolSet.StaticToolMetadata {
trimmedName := strings.TrimSpace(name)
if trimmedName == "" {
continue
}
item.ToolCode = strings.TrimSpace(item.ToolCode)
item.ServerCode = strings.TrimSpace(item.ServerCode)
item.ToolName = strings.TrimSpace(item.ToolName)
ret[trimmedName] = item
}
return ret
}
func staticToolCodeList(toolSet *registry.ToolSet) []string {
if toolSet == nil {
return nil
}
metadata := toolSetStaticToolMetadata(toolSet)
ret := make([]string, 0, len(metadata))
for _, item := range metadata {
code := strings.TrimSpace(item.ToolCode)
if code == "" {
continue
}
ret = appendIfMissing(ret, code)
}
if len(ret) > 0 {
return ret
}
for _, code := range toolSetStaticToolCodes(toolSet) {
code = strings.TrimSpace(code)
if code == "" {
continue
}
ret = appendIfMissing(ret, code)
}
return ret
}
func definitionToolCodes(defs []runtimetooling.MCPToolDefinition) []string {
ret := make([]string, 0, len(defs))
for _, item := range defs {
code := strings.TrimSpace(item.ToolCode)
if code == "" {
continue
}
ret = append(ret, code)
}
return ret
}
func filterToolDefinitionsBySkill(defs []runtimetooling.MCPToolDefinition, skill *models.SkillDefinition) []runtimetooling.MCPToolDefinition {
if skill == nil || strings.TrimSpace(skill.ToolWhitelist) == "" {
return defs
}
var allowed []string
if err := json.Unmarshal([]byte(skill.ToolWhitelist), &allowed); err != nil {
return defs
}
allowedSet := make(map[string]struct{}, len(allowed))
for _, item := range allowed {
item = toolx.NormalizeToolCodeAlias(item)
if strings.TrimSpace(item) == "" {
continue
}
allowedSet[strings.TrimSpace(item)] = struct{}{}
}
if len(allowedSet) == 0 {
return defs
}
ret := make([]runtimetooling.MCPToolDefinition, 0, len(defs))
for _, item := range defs {
if _, ok := allowedSet[strings.TrimSpace(item.ToolCode)]; ok {
ret = append(ret, item)
}
}
return ret
}
func parseJSONArrayList(raw string) []string {
raw = strings.TrimSpace(raw)
if raw == "" {
return nil
}
var items []string
if err := json.Unmarshal([]byte(raw), &items); err != nil {
return nil
}
ret := make([]string, 0, len(items))
for _, item := range items {
item = strings.TrimSpace(item)
if item == "" {
continue
}
ret = append(ret, item)
}
return ret
}