Skip to content

Commit

Permalink
🚜 Move the config providers out to the side
Browse files Browse the repository at this point in the history
  • Loading branch information
wesen committed Feb 12, 2025
1 parent 55d1240 commit f568048
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 67 deletions.
18 changes: 17 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -1030,4 +1030,20 @@ Refactored YAML editor to have a more maintainable and recursive value node crea
- Extracted value node creation logic into a dedicated CreateValueNode method
- Made value creation process recursive for nested structures
- Improved error handling with more specific error messages
- Centralized value node creation logic for better maintainability
- Centralized value node creation logic for better maintainability

# Refactor Tool Provider Creation

Extracted tool provider creation logic from start command to config package for better code organization and reusability.

- Moved tool provider creation logic to pkg/tools/providers/config/
- Added CreateToolProviderFromConfig and CreateToolProviderFromDirectories functions
- Simplified start command by using the new functions

# Move Tool Provider to Dedicated Package

Moved the configuration-based tool provider to a dedicated package for better code organization.

- Moved tool provider code to pkg/tools/providers/config/
- Updated imports and type references
- Improved package documentation
63 changes: 20 additions & 43 deletions cmd/go-go-mcp/cmds/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ import (
"syscall"
"time"

"github.com/go-go-golems/clay/pkg/repositories"
"github.com/go-go-golems/glazed/pkg/cmds"
"github.com/go-go-golems/glazed/pkg/cmds/layers"
"github.com/go-go-golems/glazed/pkg/cmds/parameters"
"github.com/go-go-golems/go-go-mcp/pkg/server"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"

"github.com/go-go-golems/go-go-mcp/pkg"
"github.com/go-go-golems/go-go-mcp/pkg/config"
config_provider "github.com/go-go-golems/go-go-mcp/pkg/tools/providers/config-provider"
)

type StartCommandSettings struct {
Expand Down Expand Up @@ -110,64 +111,40 @@ func (c *StartCommand) Run(
srv := server.NewServer(log.Logger)

// Create tool provider options
toolProviderOptions := []config.ConfigToolProviderOption{
config.WithDebug(s.Debug),
toolProviderOptions := []config_provider.ConfigToolProviderOption{
config_provider.WithDebug(s.Debug),
}
if s.TracingDir != "" {
toolProviderOptions = append(toolProviderOptions, config.WithTracingDir(s.TracingDir))
toolProviderOptions = append(toolProviderOptions, config_provider.WithTracingDir(s.TracingDir))
}

// Handle configuration file if provided
var toolProvider pkg.ToolProvider
var err error

// Try to create tool provider from config file first
if s.ConfigFile != "" {
cfg, err := config.LoadFromFile(s.ConfigFile)
toolProvider, err = config_provider.CreateToolProviderFromConfig(s.ConfigFile, s.Profile, toolProviderOptions...)
if err != nil {
if !os.IsNotExist(err) || len(s.Repositories) == 0 {
fmt.Fprintf(os.Stderr, "Run 'go-go-mcp config init' to create a starting configuration file, and further edit it with 'go-go-mcp config edit'\n")
return errors.Wrap(err, "failed to load configuration file")
}
// Config file doesn't exist but we have repositories, continue
log.Warn().Str("config", s.ConfigFile).Msg("Configuration file not found, continuing with provided repositories")
} else {
// Determine profile
profile := s.Profile
if profile == "" {
profile = cfg.DefaultProfile
return errors.Wrap(err, "failed to create tool provider from config")
}

toolProviderOptions = append(toolProviderOptions, config.WithConfig(cfg, profile))
// Config file doesn't exist but we have repositories, continue with directories
}
}

// Handle repository directories
if len(s.Repositories) > 0 {
directories := []repositories.Directory{}
for _, repoPath := range s.Repositories {
dir := os.ExpandEnv(repoPath)
// check if dir exists
if fi, err := os.Stat(dir); os.IsNotExist(err) || !fi.IsDir() {
log.Warn().Str("path", dir).Msg("Repository directory does not exist or is not a directory")
continue
}
directories = append(directories, repositories.Directory{
FS: os.DirFS(dir),
RootDirectory: ".",
RootDocDirectory: "doc",
WatchDirectory: dir,
Name: dir,
SourcePrefix: "file",
})
}

if len(directories) > 0 {
toolProviderOptions = append(toolProviderOptions, config.WithDirectories(directories))
// If no tool provider yet and we have repositories, create from directories
if toolProvider == nil && len(s.Repositories) > 0 {
toolProvider, err = config_provider.CreateToolProviderFromDirectories(s.Repositories, toolProviderOptions...)
if err != nil {
return errors.Wrap(err, "failed to create tool provider from directories")
}
}

// Create and register tool provider
toolProvider, err := config.NewConfigToolProvider(toolProviderOptions...)
if err != nil {
return errors.Wrap(err, "failed to create tool provider")
if toolProvider == nil {
return fmt.Errorf("no valid configuration source found (neither config file nor repositories)")
}

srv.GetRegistry().RegisterToolProvider(toolProvider)

// Create root context with cancellation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package config
package config_provider

import (
"os"
Expand All @@ -8,6 +8,7 @@ import (
"github.com/go-go-golems/glazed/pkg/cmds"
"github.com/go-go-golems/glazed/pkg/help"
"github.com/go-go-golems/go-go-mcp/pkg"
"github.com/go-go-golems/go-go-mcp/pkg/config"
"github.com/go-go-golems/go-go-mcp/pkg/protocol"
"github.com/pkg/errors"
)
Expand All @@ -16,17 +17,17 @@ import (
type ConfigPromptProvider struct {
repository *repositories.Repository
pinocchioFiles map[string]*protocol.Prompt
promptConfigs map[string]*SourceConfig
promptConfigs map[string]*config.SourceConfig
}

func NewConfigPromptProvider(config *Config, profile string) (*ConfigPromptProvider, error) {
if _, ok := config.Profiles[profile]; !ok {
func NewConfigPromptProvider(config_ *config.Config, profile string) (*ConfigPromptProvider, error) {
if _, ok := config_.Profiles[profile]; !ok {
return nil, errors.Errorf("profile %s not found", profile)
}

directories := []repositories.Directory{}

profileConfig := config.Profiles[profile]
profileConfig := config_.Profiles[profile]

// Load directories using Clay's repository system
for _, dir := range profileConfig.Prompts.Directories {
Expand All @@ -45,7 +46,7 @@ func NewConfigPromptProvider(config *Config, profile string) (*ConfigPromptProvi
provider := &ConfigPromptProvider{
repository: repositories.NewRepository(repositories.WithDirectories(directories...)),
pinocchioFiles: make(map[string]*protocol.Prompt),
promptConfigs: make(map[string]*SourceConfig),
promptConfigs: make(map[string]*config.SourceConfig),
}

if profileConfig.Prompts == nil {
Expand Down
2 changes: 2 additions & 0 deletions pkg/prompts/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type Registry struct {
handlers map[string]Handler
}

var _ pkg.PromptProvider = &Registry{}

// Handler is a function that generates a prompt message based on arguments
type Handler func(prompt protocol.Prompt, arguments map[string]string) (*protocol.PromptMessage, error)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package config
package config_provider

import (
"context"
Expand All @@ -15,16 +15,18 @@ import (
"github.com/go-go-golems/glazed/pkg/help"
"github.com/go-go-golems/go-go-mcp/pkg"
mcp_cmds "github.com/go-go-golems/go-go-mcp/pkg/cmds"
"github.com/go-go-golems/go-go-mcp/pkg/config"
"github.com/go-go-golems/go-go-mcp/pkg/protocol"
"github.com/go-go-golems/parka/pkg/handlers/config"
parka_config "github.com/go-go-golems/parka/pkg/handlers/config"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)

// ConfigToolProvider implements pkg.ToolProvider interface
type ConfigToolProvider struct {
repository *repositories.Repository
shellCommands map[string]cmds.Command
toolConfigs map[string]*SourceConfig
toolConfigs map[string]*config.SourceConfig
helpSystem *help.HelpSystem
debug bool
tracingDir string
Expand All @@ -33,6 +35,8 @@ type ConfigToolProvider struct {

type ConfigToolProviderOption func(*ConfigToolProvider) error

var _ pkg.ToolProvider = &ConfigToolProvider{}

func WithDebug(debug bool) ConfigToolProviderOption {
return func(p *ConfigToolProvider) error {
p.debug = debug
Expand All @@ -54,9 +58,9 @@ func WithDirectories(directories []repositories.Directory) ConfigToolProviderOpt
}
}

func WithConfig(config *Config, profile string) ConfigToolProviderOption {
func WithConfig(config_ *config.Config, profile string) ConfigToolProviderOption {
return func(p *ConfigToolProvider) error {
profileConfig, ok := config.Profiles[profile]
profileConfig, ok := config_.Profiles[profile]
if !ok {
return errors.Errorf("profile %s not found", profile)
}
Expand Down Expand Up @@ -107,7 +111,7 @@ func WithConfig(config *Config, profile string) ConfigToolProviderOption {
func NewConfigToolProvider(options ...ConfigToolProviderOption) (*ConfigToolProvider, error) {
provider := &ConfigToolProvider{
shellCommands: make(map[string]cmds.Command),
toolConfigs: make(map[string]*SourceConfig),
toolConfigs: make(map[string]*config.SourceConfig),
helpSystem: help.NewHelpSystem(),
directories: []repositories.Directory{},
}
Expand Down Expand Up @@ -265,48 +269,102 @@ func (p *ConfigToolProvider) executeCommand(ctx context.Context, cmd cmds.Comman
return protocol.NewToolResult(protocol.WithText(text)), nil
}

func (p *ConfigToolProvider) createParkaParameterFilter(sourceConfig *SourceConfig) *config.ParameterFilter {
options := []config.ParameterFilterOption{}
func (p *ConfigToolProvider) createParkaParameterFilter(sourceConfig *config.SourceConfig) *parka_config.ParameterFilter {
options := []parka_config.ParameterFilterOption{}

// Handle defaults
if sourceConfig.Defaults != nil {
layerParams := config.NewLayerParameters()
layerParams := parka_config.NewLayerParameters()
for layer, params := range sourceConfig.Defaults {
layerParams.Layers[layer] = params
}
options = append(options, config.WithReplaceDefaults(layerParams))
options = append(options, parka_config.WithReplaceDefaults(layerParams))
}

// Handle overrides
if sourceConfig.Overrides != nil {
layerParams := config.NewLayerParameters()
layerParams := parka_config.NewLayerParameters()
for layer, params := range sourceConfig.Overrides {
layerParams.Layers[layer] = params
}
options = append(options, config.WithReplaceOverrides(layerParams))
options = append(options, parka_config.WithReplaceOverrides(layerParams))
}

// Handle whitelist
if sourceConfig.Whitelist != nil {
whitelist := &config.ParameterFilterList{}
whitelist := &parka_config.ParameterFilterList{}
for layer, params := range sourceConfig.Whitelist {
whitelist.LayerParameters = map[string][]string{
layer: params,
}
}
options = append(options, config.WithWhitelist(whitelist))
options = append(options, parka_config.WithWhitelist(whitelist))
}

// Handle blacklist
if sourceConfig.Blacklist != nil {
blacklist := &config.ParameterFilterList{}
blacklist := &parka_config.ParameterFilterList{}
for layer, params := range sourceConfig.Blacklist {
blacklist.LayerParameters = map[string][]string{
layer: params,
}
}
options = append(options, config.WithBlacklist(blacklist))
options = append(options, parka_config.WithBlacklist(blacklist))
}

return parka_config.NewParameterFilter(options...)
}

// CreateToolProviderFromConfig creates a tool provider from a config file and profile
func CreateToolProviderFromConfig(configFile string, profile string, options ...ConfigToolProviderOption) (*ConfigToolProvider, error) {
// Handle configuration file if provided
if configFile != "" {
cfg, err := config.LoadFromFile(configFile)
if err != nil {
if !os.IsNotExist(err) {
return nil, errors.Wrap(err, "failed to load configuration file")
}
// Config file doesn't exist, continue with other options
log.Warn().Str("config", configFile).Msg("Configuration file not found")
} else {
// Determine profile
if profile == "" {
profile = cfg.DefaultProfile
}

options = append(options, WithConfig(cfg, profile))
}
}

// Create and return tool provider
return NewConfigToolProvider(options...)
}

// CreateToolProviderFromDirectories creates a tool provider from a list of directories
func CreateToolProviderFromDirectories(directories []string, options ...ConfigToolProviderOption) (*ConfigToolProvider, error) {
if len(directories) > 0 {
dirs := []repositories.Directory{}
for _, repoPath := range directories {
dir := os.ExpandEnv(repoPath)
// check if dir exists
if fi, err := os.Stat(dir); os.IsNotExist(err) || !fi.IsDir() {
log.Warn().Str("path", dir).Msg("Repository directory does not exist or is not a directory")
continue
}
dirs = append(dirs, repositories.Directory{
FS: os.DirFS(dir),
RootDirectory: ".",
RootDocDirectory: "doc",
WatchDirectory: dir,
Name: dir,
SourcePrefix: "file",
})
}

if len(dirs) > 0 {
options = append(options, WithDirectories(dirs))
}
}

return config.NewParameterFilter(options...)
return NewConfigToolProvider(options...)
}
2 changes: 2 additions & 0 deletions pkg/tools/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type Registry struct {
// Handler is a function that executes a tool with given arguments
type Handler func(ctx context.Context, tool Tool, arguments map[string]interface{}) (*protocol.ToolResult, error)

var _ pkg.ToolProvider = &Registry{}

// NewRegistry creates a new tool registry
func NewRegistry() *Registry {
return &Registry{
Expand Down

0 comments on commit f568048

Please sign in to comment.