diff --git a/internal/cli/flags.go b/internal/cli/flags.go index a1b7e82a..fc42ba44 100644 --- a/internal/cli/flags.go +++ b/internal/cli/flags.go @@ -102,26 +102,34 @@ func Init() (ret *Flags, err error) { usedFlags := make(map[string]bool) yamlArgsScan := os.Args[1:] - // Get list of fields that have yaml tags, could be in yaml config - yamlFields := make(map[string]bool) + // Create mapping from flag names (both short and long) to yaml tag names + flagToYamlTag := make(map[string]string) t := reflect.TypeOf(Flags{}) for i := 0; i < t.NumField(); i++ { - if yamlTag := t.Field(i).Tag.Get("yaml"); yamlTag != "" { - yamlFields[yamlTag] = true - //Debugf("Found yaml-configured field: %s\n", yamlTag) + field := t.Field(i) + yamlTag := field.Tag.Get("yaml") + if yamlTag != "" { + longTag := field.Tag.Get("long") + shortTag := field.Tag.Get("short") + if longTag != "" { + flagToYamlTag[longTag] = yamlTag + Debugf("Mapped long flag %s to yaml tag %s\n", longTag, yamlTag) + } + if shortTag != "" { + flagToYamlTag[shortTag] = yamlTag + Debugf("Mapped short flag %s to yaml tag %s\n", shortTag, yamlTag) + } } } // Scan args for that are provided by cli and might be in yaml for _, arg := range yamlArgsScan { - if strings.HasPrefix(arg, "--") { - flag := strings.TrimPrefix(arg, "--") - if i := strings.Index(flag, "="); i > 0 { - flag = flag[:i] - } - if yamlFields[flag] { - usedFlags[flag] = true - Debugf("CLI flag used: %s\n", flag) + flag := extractFlag(arg) + + if flag != "" { + if yamlTag, exists := flagToYamlTag[flag]; exists { + usedFlags[yamlTag] = true + Debugf("CLI flag used: %s (yaml: %s)\n", flag, yamlTag) } } } @@ -134,6 +142,16 @@ func Init() (ret *Flags, err error) { return } + // Check to see if a ~/.fabric.yaml config file exists (only when user didn't specify a config) + if ret.Config == "" { + // Default to ~/.fabric.yaml if no config specified + if defaultConfigPath, err := util.GetDefaultConfigPath(); err == nil && defaultConfigPath != "" { + ret.Config = defaultConfigPath + } else if err != nil { + Debugf("Could not determine default config path: %v\n", err) + } + } + // If config specified, load and apply YAML for unused flags if ret.Config != "" { var yamlFlags *Flags @@ -168,7 +186,6 @@ func Init() (ret *Flags, err error) { } } - // Handle stdin and messages // Handle stdin and messages info, _ := os.Stdin.Stat() pipedToStdin := (info.Mode() & os.ModeCharDevice) == 0 @@ -188,6 +205,22 @@ func Init() (ret *Flags, err error) { return } +func extractFlag(arg string) string { + var flag string + if strings.HasPrefix(arg, "--") { + flag = strings.TrimPrefix(arg, "--") + if i := strings.Index(flag, "="); i > 0 { + flag = flag[:i] + } + } else if strings.HasPrefix(arg, "-") && len(arg) > 1 { + flag = strings.TrimPrefix(arg, "-") + if i := strings.Index(flag, "="); i > 0 { + flag = flag[:i] + } + } + return flag +} + func assignWithConversion(targetField, sourceField reflect.Value) error { // Handle string source values if sourceField.Kind() == reflect.String { diff --git a/internal/core/chatter.go b/internal/core/chatter.go index 6af5b5b9..78410c6a 100644 --- a/internal/core/chatter.go +++ b/internal/core/chatter.go @@ -103,7 +103,7 @@ func (o *Chatter) Send(request *domain.ChatRequest, opts *domain.ChatOptions) (s } } - if opts.SuppressThink { + if opts.SuppressThink && !o.DryRun { message = domain.StripThinkBlocks(message, opts.ThinkStartTag, opts.ThinkEndTag) } diff --git a/internal/plugins/ai/dryrun/dryrun.go b/internal/plugins/ai/dryrun/dryrun.go index d962522b..6a3f903e 100644 --- a/internal/plugins/ai/dryrun/dryrun.go +++ b/internal/plugins/ai/dryrun/dryrun.go @@ -12,6 +12,8 @@ import ( "github.com/danielmiessler/fabric/internal/plugins" ) +const DryRunResponse = "Dry run: Fake response sent by DryRun plugin\n" + type Client struct { *plugins.PluginBase } @@ -85,27 +87,37 @@ func (c *Client) formatOptions(opts *domain.ChatOptions) string { if opts.ImageFile != "" { builder.WriteString(fmt.Sprintf("ImageFile: %s\n", opts.ImageFile)) } + if opts.SuppressThink { + builder.WriteString("SuppressThink: enabled\n") + builder.WriteString(fmt.Sprintf("Thinking Start Tag: %s\n", opts.ThinkStartTag)) + builder.WriteString(fmt.Sprintf("Thinking End Tag: %s\n", opts.ThinkEndTag)) + } return builder.String() } -func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) error { +func (c *Client) constructRequest(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions) string { var builder strings.Builder builder.WriteString("Dry run: Would send the following request:\n\n") builder.WriteString(c.formatMessages(msgs)) builder.WriteString(c.formatOptions(opts)) - channel <- builder.String() - close(channel) + return builder.String() +} + +func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions, channel chan string) error { + defer close(channel) + request := c.constructRequest(msgs, opts) + channel <- request + channel <- "\n" + channel <- DryRunResponse return nil } func (c *Client) Send(_ context.Context, msgs []*chat.ChatCompletionMessage, opts *domain.ChatOptions) (string, error) { - fmt.Println("Dry run: Would send the following request:") - fmt.Print(c.formatMessages(msgs)) - fmt.Print(c.formatOptions(opts)) + request := c.constructRequest(msgs, opts) - return "", nil + return request + "\n" + DryRunResponse, nil } func (c *Client) Setup() error { diff --git a/internal/util/utils.go b/internal/util/utils.go index c59819e6..c4f40ca7 100644 --- a/internal/util/utils.go +++ b/internal/util/utils.go @@ -71,3 +71,21 @@ func IsSymlinkToDir(path string) bool { return false // Regular directories should not be treated as symlinks } + +// GetDefaultConfigPath returns the default path for the configuration file +// if it exists, otherwise returns an empty string. +func GetDefaultConfigPath() (string, error) { + homeDir, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("could not determine user home directory: %w", err) + } + + defaultConfigPath := filepath.Join(homeDir, ".fabric.yaml") + if _, err := os.Stat(defaultConfigPath); err != nil { + if os.IsNotExist(err) { + return "", nil // Return no error for non-existent config path + } + return "", fmt.Errorf("error accessing default config path: %w", err) + } + return defaultConfigPath, nil +}