package sidekick import ( "encoding/json" "fmt" "regexp" ) // ToolDefinition represents a registered tool type ToolDefinition struct { Name string Description string Parameters map[string]interface{} // JSON Schema Toolset string // MCP server name Internal bool // If true, bypasses MCP Handler ToolHandler // Used if Internal is true } // ToolHandler is a function type for internal tools type ToolHandler func(args map[string]interface{}) (string, error) var nonAlphaNumRegex = regexp.MustCompile(`[^a-zA-Z0-9_\-]`) // SanitizeToolName converts arbitrary names (like "mcp/tool") into safe names ("mcp_tool") func SanitizeToolName(name string) string { return nonAlphaNumRegex.ReplaceAllString(name, "_") } // ConvertToOpenAITool formats the tool for the LLM API func (t *ToolDefinition) ConvertToOpenAITool() map[string]interface{} { sanitized := SanitizeToolName(t.Name) params := t.Parameters if params == nil { params = map[string]interface{}{ "type": "object", "properties": map[string]interface{}{}, } } return map[string]interface{}{ "type": "function", "function": map[string]interface{}{ "name": sanitized, "description": t.Description, "parameters": params, }, } } // ParseArgs parses JSON string arguments into a map func ParseArgs(argsStr string) (map[string]interface{}, error) { var args map[string]interface{} if argsStr == "" { return make(map[string]interface{}), nil } err := json.Unmarshal([]byte(argsStr), &args) if err != nil { return nil, fmt.Errorf("failed to parse tool arguments: %w", err) } return args, nil }